diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 8ea4dba0..acd6545c 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -17,10 +17,10 @@ name: Build Open Banking Repository on: - # Triggers the workflow on push or pull request events but only for the master branch + # Triggers the workflow on push or pull request events pull_request: branches: - - 'main' + - '3.0.0' jobs: diff --git a/open-banking-accelerator/accelerators/ob-apim/bin/configure.ps1 b/open-banking-accelerator/accelerators/ob-apim/bin/configure.ps1 index 1dcf8ac8..e5264d46 100644 --- a/open-banking-accelerator/accelerators/ob-apim/bin/configure.ps1 +++ b/open-banking-accelerator/accelerators/ob-apim/bin/configure.ps1 @@ -1,4 +1,4 @@ - # Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + # Copyright (c) 2023-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 @@ -14,153 +14,239 @@ # specific language governing permissions and limitations # under the License. -# command to execute -# ./configure.ps1 +# How to execute : +# If your accelerator is located inside of the base product you can just call .\configure.ps1 +# If your accelerator is in a different location you can call .\configure.ps1 + +# IMPORTANT : +# Please note that these powershell files are not digitally signed yet. So, powershell will not allow these scripts under any of their execution policies. +# You may need to run these scripts on an execution policy bypassed powershell instance. You can do that using the following command. +# powershell.exe -executionpolicy bypass + +# Get the current working directory of the powershell session, so we can set to this directory after the script finishes. +$CURRENT_DIRECTORY = (Get-Location).path + +# Some black magic to get the fully qualified path of the WSO2 Base Product if it was given as an argument. +$WSO2_BASE_PRODUCT_HOME = $args[0] +if (-NOT($null -eq $WSO2_BASE_PRODUCT_HOME)) { + if (Test-Path $WSO2_BASE_PRODUCT_HOME) { + Set-Location $WSO2_BASE_PRODUCT_HOME + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path + Set-Location $CURRENT_DIRECTORY + } +} -$Props = convertfrom-stringdata (get-content ./../repository/conf/configure.properties -raw) -$WSO2_OB_APIM_HOME = $args[0] +Function Exit-Clean { + Set-Location $CURRENT_DIRECTORY + exit 1 +} -# set accelerator home -Set-Location ../ -$ACCELERATOR_HOME = $pwd.path -Write-Output "Accelerator Home: $ACCELERATOR_HOME" +# A utility function to Find and Replace texts in a file. +Function Find-Replace { + param( + [string]$FILE_PATH, + [string]$OLD_TEXT, + [string]$NEW_TEXT + ) -# set product home -if ($null -eq $WSO2_OB_APIM_HOME) -{ - Set-Location ../ - $WSO2_OB_APIM_HOME = $pwd.path - Write-Output "Product Home: $WSO2_OB_APIM_HOME" + # Read the file content + $CONTENT = Get-Content $FILE_PATH -Raw + + # Escape special characters in OLD_TEXT for the regex + $escapedOldText = [regex]::Escape($OLD_TEXT) + + # Define the regex pattern to consider non-word characters as boundaries + $regex = "(?// +Set-Location (Join-Path $PSScriptRoot ".\..\") +$WSO2_OB_ACCELERATOR_HOME = (Get-Location).path +Write-Output "[INFO] Accelerator Home : $WSO2_OB_ACCELERATOR_HOME" + +# Get the root directory of the base product. +if ($null -eq $WSO2_BASE_PRODUCT_HOME) { + Set-Location (Join-Path $WSO2_OB_ACCELERATOR_HOME ".\..\") + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path } -else -{ - Write-Output "`nValid carbon product path.`n" +Write-Output "[INFO] Base Product Home : $WSO2_BASE_PRODUCT_HOME" + +# Check whether the extracted base product location contains a valid WSO2 carbon product by checking whether this location +# contains the "repository/components" directory. +if (-NOT(Test-Path (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components"))) { + Write-Output "[ERROR] $WSO2_BASE_PRODUCT_HOME does NOT contain a valid carbon product!" + # The current path does not contain a valid carbon product. + # Set the current working directory to the original location and exit. + Exit-Clean +} else { + Write-Output "[INFO] $WSO2_BASE_PRODUCT_HOME is a valid carbon product home." } -# read deployment.toml file -$DEPLOYMENT_TOML_FILE = "$ACCELERATOR_HOME/repository/resources/deployment.toml" -Copy-Item -Path "$ACCELERATOR_HOME/$( $Props.'PRODUCT_CONF_PATH' )" $DEPLOYMENT_TOML_FILE +# Get the location of the configure.properties +$CONFIG_PROPERTIES_PATH = Join-Path $WSO2_OB_ACCELERATOR_HOME "repository\conf\configure.properties" +Write-Output "[INFO] configure.properties location : $CONFIG_PROPERTIES_PATH" + +# Load the variables in the configure.properties file +$PROPERTIES = ConvertFrom-StringData (Get-Content $CONFIG_PROPERTIES_PATH -raw) + +$SELECTED_DEPLOYMENT_TOML_FILE = Join-Path $WSO2_OB_ACCELERATOR_HOME $PROPERTIES.'PRODUCT_CONF_PATH' +Write-Output "[INFO] Selected deployment.toml location : $SELECTED_DEPLOYMENT_TOML_FILE" + +$DEPLOYMENT_TOML_FILE = Join-Path $WSO2_OB_ACCELERATOR_HOME "repository\resources\deployment.toml" +# Temporary copy the selected toml file so we can make changes to it. +Copy-Item -Path $SELECTED_DEPLOYMENT_TOML_FILE $DEPLOYMENT_TOML_FILE +Write-Output "[INFO] Temporary deployment.toml location : $DEPLOYMENT_TOML_FILE" -Function Configure-Datasources +# A function to replace the database related variables in the temp deployment.toml with their actual values from configure.properties +Function Set-Datasources { - if ($Props.'DB_TYPE' -eq "mysql") + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { - # APIM - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_APIMGT_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_APIMGT' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_AM_CONFIG_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_AM_CONFIG' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_GOV_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_GOV' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER_STORE_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_USER_STORE' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER", "$( $Props.'DB_USER' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_PASS", "$( $Props.'DB_PASS' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_DRIVER", "$( $Props.'DB_DRIVER' )" }) + # MySQL + Find-Replace $DEPLOYMENT_TOML_FILE "DB_APIMGT_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_APIMGT' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_AM_CONFIG_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_AM_CONFIG' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_GOV_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_GOV' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER_STORE_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_USER_STORE' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER" "$( $PROPERTIES.'DB_USER' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_PASS" "$( $PROPERTIES.'DB_PASS' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_DRIVER" "$( $PROPERTIES.'DB_DRIVER' )" } - else + elseif($PROPERTIES.'DB_TYPE' -eq "mssql") { - # IS - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_APIMGT_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_APIMGT' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_AM_CONFIG_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_AM_CONFIG' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_GOV_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_GOV' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER_STORE_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_USER_STORE' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER", "$( $Props.'DB_USER' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_PASS", "$( $Props.'DB_PASS' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_DRIVER", "$( $Props.'DB_DRIVER' )" }) + # Microsoft SQL Server + Find-Replace $DEPLOYMENT_TOML_FILE "DB_APIMGT_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_APIMGT' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_AM_CONFIG_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_AM_CONFIG' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_GOV_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_GOV' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER_STORE_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_USER_STORE' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER" "$( $PROPERTIES.'DB_USER' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_PASS" "$( $PROPERTIES.'DB_PASS' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_DRIVER" "$( $PROPERTIES.'DB_DRIVER' )" + } + else { + Write-Output "[ERROR] Unsupported Database Type!" + Exit-Clean } } -Function Create-Databases -{ - if ($Props.'DB_TYPE' -eq "mysql") - { - if ($Props.'DB_PASS' -eq "") - { - $DB_MYSQL_PASS = "" - } - else - { - $DB_MYSQL_PASS = $Props.'DB_PASS' - } - Write-Output "`nCreating MySQL databases" - Write-Output "================================================`n" - Create-Mysql-Databases +# A function to replace the hostname related variables in the temp deployment.toml with their actual values from configure.properties +Function Set-Hostnames { + Find-Replace $DEPLOYMENT_TOML_FILE "APIM_HOSTNAME" "$( $PROPERTIES.'APIM_HOSTNAME' )" + Find-Replace $DEPLOYMENT_TOML_FILE "IS_HOSTNAME" "$( $PROPERTIES.'IS_HOSTNAME' )" + Find-Replace $DEPLOYMENT_TOML_FILE "BI_HOSTNAME" "$( $PROPERTIES.'BI_HOSTNAME' )" +} - Write-Output "`nUpdate am_application_registration table input field size (temporary)" - Write-Output "=======================================================================`n" - Set-Content -Path $WSO2_OB_APIM_HOME/dbscripts/apimgt/mysql.sql -Value (get-content $WSO2_OB_APIM_HOME/dbscripts/apimgt/mysql.sql | ForEach-Object{ $_ -replace "INPUTS VARCHAR(1000)", "INPUTS VARCHAR(7500)" }) +# A utility function to create a database. +Function Add-Database { + param ([string]$DB_USER, [string]$DB_PASS, [string]$DB_HOST, [string]$DB_NAME) + mysql -u"$($DB_USER)" -p"$($DB_PASS)" -h"$($DB_HOST)" -e "DROP DATABASE IF EXISTS $($DB_NAME); CREATE DATABASE $( $DB_NAME ) DEFAULT CHARACTER SET latin1;" +} - Write-Output "`nCreate database tables" - Write-Output "================================================`n" - Create-Mysql-DatabaseTables +# A utility function to create a table inside a given database. +Function Add-TablesToDatabase { + param ([string]$DB_USER, [string]$DB_PASS, [string]$DB_HOST, [string]$DB_NAME, [string]$DB_SOURCE) + mysql -u"$($DB_USER)" -p"$($DB_PASS)" -h"$($DB_HOST)" -D"$($DB_NAME)" -e "SOURCE $($DB_SOURCE)" +} - Write-Output "`nAlter SP_METADATA table VALUE field size (temporary)" - Write-Output "=======================================================================`n" - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"ALTER TABLE $( $Props.'DB_APIMGT' ).SP_METADATA MODIFY VALUE VARCHAR(4096);" - } - else - { - Write-Output "`nAssume MSSQL/Oracle databases have already created manually" +# A function to create the databases. ONLY SUPPORTED FOR THE MYSQL +Function Add-Databases { + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { + $DB_MYSQL_PASS = "" + if (-NOT($PROPERTIES.'DB_PASS' -eq "")) { + $DB_MYSQL_PASS = $PROPERTIES.'DB_PASS' + } - Write-Output "`nUpdate idn_req_object_reference table foreign keys (temporary)" - Write-Output "=======================================================================`n" - Set-Content -Path $WSO2_OB_APIM_HOME/dbscripts/apimgt/mssql.sql -Value (get-content $WSO2_OB_APIM_HOME/dbscripts/apimgt/mssql.sql | ForEach-Object{ $_ -replace "FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE ,", "FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID)," }) - Set-Content -Path $WSO2_OB_APIM_HOME/dbscripts/apimgt/mssql.sql -Value (get-content $WSO2_OB_APIM_HOME/dbscripts/apimgt/mssql.sql | ForEach-Object{ $_ -replace "FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID),", "FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID) ON DELETE CASCADE," }) + Add-Database "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_APIMGT' )" + Write-Output "[INFO] Database Created: $( $PROPERTIES.'DB_APIMGT' )" + + Add-Database "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_AM_CONFIG' )" + Write-Output "[INFO] Database Created: $( $PROPERTIES.'DB_AM_CONFIG' )" + + Add-Database "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_GOV' )" + Write-Output "[INFO] Database Created: $( $PROPERTIES.'DB_GOV' )" + + Add-Database "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_USER_STORE' )" + Write-Output "[INFO] Database Created: $( $PROPERTIES.'DB_USER_STORE' )" + } + else { + Write-Output "[INFO] The databases must be created manually for non mysql DBMSs." } } -Function Create-Mysql-Databases -{ - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_APIMGT' ); CREATE DATABASE $( $Props.'DB_APIMGT' ); ALTER DATABASE $( $Props.'DB_APIMGT' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_APIMGT' )" - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_AM_CONFIG' ); CREATE DATABASE $( $Props.'DB_AM_CONFIG' ); ALTER DATABASE $( $Props.'DB_AM_CONFIG' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_AM_CONFIG' )" - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_GOV' ); CREATE DATABASE $( $Props.'DB_GOV' ); ALTER DATABASE $( $Props.'DB_GOV' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_GOV' )" - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_USER_STORE' ); CREATE DATABASE $( $Props.'DB_USER_STORE' ); ALTER DATABASE $( $Props.'DB_USER_STORE' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_USER_STORE' )" -} +# A function to create the database tables. ONLY SUPPORTED FOR THE MYSQL +Function Add-DatabaseTables { + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { -Function Create-Mysql-DatabaseTables -{ - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_APIMGT' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_APIM_HOME\dbscripts\apimgt\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_APIMGT' )" - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_AM_CONFIG' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_APIM_HOME\dbscripts\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_AM_CONFIG' )" - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_GOV' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_APIM_HOME\dbscripts\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_GOV' )" - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_USER_STORE' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_APIM_HOME\dbscripts\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_USER_STORE' )" + Write-Output "[NOTE] Update am_application_registration table input field size (temporary)" + Find-Replace (Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\apimgt\mysql.sql") "INPUTS VARCHAR(1000)," "INPUTS VARCHAR(7500)," + + $DB_MYSQL_PASS = "" + if (-NOT($PROPERTIES.'DB_PASS' -eq "")) { + $DB_MYSQL_PASS = $PROPERTIES.'DB_PASS' + } + + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_APIMGT' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\apimgt\mysql.sql")" + Write-Output "[NOTE] Database tables Created for: $( $PROPERTIES.'DB_APIMGT' )" + + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_AM_CONFIG' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\mysql.sql")" + Write-Output "[NOTE] Database tables Created for: $( $PROPERTIES.'DB_AM_CONFIG' )" + + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_GOV' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\mysql.sql")" + Write-Output "[NOTE] Database tables Created for: $( $PROPERTIES.'DB_GOV' )" + + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" $DB_MYSQL_PASS "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_USER_STORE' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\mysql.sql")" + Write-Output "[NOTE] Database tables Created for: $( $PROPERTIES.'DB_USER_STORE' )" + + mysql -u"$( $PROPERTIES.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $PROPERTIES.'DB_HOST' )" -e "ALTER TABLE $( $PROPERTIES.'DB_APIMGT' ).SP_METADATA MODIFY VALUE VARCHAR(4096);" + } + else { + Write-Output "[INFO] The database tables must be created manually for non mysql DBMSs." + Find-Replace (Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\apimgt\mssql.sql") "FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE ," "FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID)," + Find-Replace (Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\apimgt\mssql.sql") "FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID)," "FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID) ON DELETE CASCADE," + } } -Function Add-Json-Fault-Sequence +Function Add-JsonFaultSequence { - Set-Content -Path $WSO2_OB_APIM_HOME/repository/deployment/server/synapse-configs/default/sequences/_cors_request_handler_.xml -Value (get-content $WSO2_OB_APIM_HOME/repository/deployment/server/synapse-configs/default/sequences/_cors_request_handler_.xml | ForEach-Object{ $_ -replace "", "`t`n" }) + Write-Output "[INFO] Adding JSON Fault Sequence..." + $CORS_REQ_HANDLER_PATH = (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\deployment\server\synapse-configs\default\sequences\_cors_request_handler_.xml") + Find-Replace $CORS_REQ_HANDLER_PATH "" "`t`n" + Write-Output "[INFO] JSON Fault Sequence added!" } -Write-Output "`nReplace hostnames `n" -Write-Output "================================================`n" -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "APIM_HOSTNAME", "$( $Props.'APIM_HOSTNAME' )" }) -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "IS_HOSTNAME", "$( $Props.'IS_HOSTNAME' )" }) -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "BI_HOSTNAME", "$( $Props.'BI_HOSTNAME' )" }) +Write-Output "============================================" +Write-Output "[INFO] Configuring the hostnames..." +Set-Hostnames +Write-Output "[INFO] Hostnames configurations completed!" -Write-Output "`nConfigure datasources `n" -Write-Output "================================================`n" -Configure-Datasources +Write-Output "============================================" +Write-Output "[INFO] Configuring the datasources..." +Set-Datasources +Write-Output "[INFO] Datasources configurations completed!" -Write-Output "`nCreate databases" -Write-Output "================================================`n" -Create-Databases +Write-Output "============================================" +Copy-Item $DEPLOYMENT_TOML_FILE (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\conf\deployment.toml") +Write-Output "[INFO] Copied temp toml to the $(Join-Path $WSO2_BASE_PRODUCT_HOME "repository\conf\deployment.toml")" -Write-Output "`nCopy deployment.toml file to repository/conf `n" -Write-Output "================================================`n" -Copy-Item $DEPLOYMENT_TOML_FILE $WSO2_OB_APIM_HOME/repository/conf/ Remove-Item $DEPLOYMENT_TOML_FILE +Write-Output "[INFO] Deleted temp toml $DEPLOYMENT_TOML_FILE" + +Write-Output "============================================" +Add-Databases + +Write-Output "============================================" +Add-DatabaseTables + +Write-Output "============================================" +Add-JsonFaultSequence + +$DEFAULT_JSON_FILE_PATH = Join-Path $WSO2_BASE_PRODUCT_HOME "repository\resources\conf\default.json" +Find-Replace $DEFAULT_JSON_FILE_PATH "`"keystore.listener_profile.bind_address`": `"0.0.0.0`"" "`"keystore.listener_profile.bind_address`": `"0:0:0:0:0:0:0:0`"" -Write-Output "`nAdd json converter for fault sequences `n" -Write-Output "================================================`n" -Add-Json-Fault-Sequence +Exit-Clean diff --git a/open-banking-accelerator/accelerators/ob-apim/bin/merge.bat b/open-banking-accelerator/accelerators/ob-apim/bin/merge.bat deleted file mode 100644 index 0dbdf773..00000000 --- a/open-banking-accelerator/accelerators/ob-apim/bin/merge.bat +++ /dev/null @@ -1,53 +0,0 @@ - REM !/bin/bash - REM Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - REM - REM WSO2 LLC. licenses this file to you under the Apache License, - REM Version 2.0 (the "License"); you may not use this file except - REM in compliance with the License. - REM You may obtain a copy of the License at - REM - REM http://www.apache.org/licenses/LICENSE-2.0 - REM - REM Unless required by applicable law or agreed to in writing, - REM software distributed under the License is distributed on an - REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - REM KIND, either express or implied. See the License for the - REM specific language governing permissions and limitations - REM under the License. - -REM merge.bat script copy the WSO2 OB APIM accelerator artifacts on top of WSO2 APIM base product -REM -REM merge.bat - -@echo off - -SET APIM_HOME=%1 - -REM set accelerator home -cd %CD%..\.. -SET WSO2_OB_ACCELERATOR_HOME=%CD% -echo "Accelerator home is: %WSO2_OB_ACCELERATOR_HOME%" - -REM set product home -if "%APIM_HOME%" == "" ( - cd %CD%..\.. - SET APIM_HOME=%CD% - echo "Product home is: %APIM_HOME%" -) - -REM validate product home -if not exist %APIM_HOME%\repository\components ( - echo "ERROR:specified product path is not a valid carbon product path" - ) else ( - echo "Valid carbon product path." - ) - -echo "Remove old open banking artifacts from base product" -del %APIM_HOME%\repository\components\dropins\com.wso2.openbanking.* -del %APIM_HOME%\repository\components\lib\com.wso2.openbanking.* - - -echo "Copying open banking artifacts" -echo ================================================ -robocopy %WSO2_OB_ACCELERATOR_HOME%\carbon-home /e %APIM_HOME% -echo "Complete!" diff --git a/open-banking-accelerator/accelerators/ob-apim/bin/merge.ps1 b/open-banking-accelerator/accelerators/ob-apim/bin/merge.ps1 new file mode 100644 index 00000000..a9846f8a --- /dev/null +++ b/open-banking-accelerator/accelerators/ob-apim/bin/merge.ps1 @@ -0,0 +1,82 @@ + # Copyright (c) 2023-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. + +# How to execute : +# If your accelerator is located inside of the base product you can just call .\merge.ps1 +# If your accelerator is in a different location you can call .\merge.ps1 + +# IMPORTANT : +# Please note that these powershell files are not digitally signed yet. So, powershell will not allow these scripts under any of their execution policies. +# You may need to run these scripts on an execution policy bypassed powershell instance. You can do that using the following command. +# powershell.exe -executionpolicy bypass + +# Get the current working directory of the powershell session, so we can set to this directory after the script finishes. +$CURRENT_DIRECTORY = (Get-Location).path + +# Some black magic to get the fully qualified path of the WSO2 Base Product if it was given as an argument. +$WSO2_BASE_PRODUCT_HOME = $args[0] +if (-NOT($null -eq $WSO2_BASE_PRODUCT_HOME)) { + if (Test-Path $WSO2_BASE_PRODUCT_HOME) { + Set-Location $WSO2_BASE_PRODUCT_HOME + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path + Set-Location $CURRENT_DIRECTORY + } +} + +Function Exit-Clean { + Set-Location $CURRENT_DIRECTORY + exit 1 +} + +# Get the root directory location of the accelerator. Which is // +Set-Location (Join-Path $PSScriptRoot ".\..\") +$WSO2_OB_ACCELERATOR_HOME = (Get-Location).path +Write-Output "[INFO] Accelerator Home : $WSO2_OB_ACCELERATOR_HOME" + +# Get the root directory of the base product. +if ($null -eq $WSO2_BASE_PRODUCT_HOME) { + Set-Location (Join-Path $WSO2_OB_ACCELERATOR_HOME ".\..\") + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path +} +Write-Output "[INFO] Base Product Home : $WSO2_BASE_PRODUCT_HOME" + +# Check whether the extracted base product location contains a valid WSO2 carbon product by checking whether this location +# contains the "repository/components" directory. +if (-NOT(Test-Path (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components"))) { + Write-Error "[ERROR] $WSO2_BASE_PRODUCT_HOME does NOT contain a valid carbon product!" + # The current path does not contain a valid carbon product. + # Set the current working directory to the original location and exit. + Exit-Clean +} else { + Write-Output "[INFO] $WSO2_BASE_PRODUCT_HOME is a valid carbon product home." +} + +# Remove old open-banking artifacts +Write-Output "[INFO] Removing old open-banking artifacts..." +Get-ChildItem (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components\dropins") | Where-Object{$_.Name -Match "com.wso2.openbanking.accelerator.*"} | Remove-Item +Get-ChildItem (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components\lib") | Where-Object{$_.Name -Match "com.wso2.openbanking.accelerator.*"} | Remove-Item +Write-Output "[INFO] All previous OB artifacts have been deleted!" + +# Copying all the new OB artifacts to the base product +# Copy-Item -Force -Recurse -Verbose (Join-Path $WSO2_OB_ACCELERATOR_HOME "carbon-home\*") -Destination $WSO2_BASE_PRODUCT_HOME +# Using Robocopy.exe becuase powershell Copy-Item cmdlet doesn't do recursive copying after a certain number of subdirectories. +Write-Output "[INFO] Copying new open-banking artifacts..." +Robocopy.exe (Join-Path $WSO2_OB_ACCELERATOR_HOME "carbon-home") $WSO2_BASE_PRODUCT_HOME * /E /NFL /NDL /NJH /NJS /nc /ns /np +Write-Output "[INFO] All the new OB artifacts has been copied!" + +Write-Output "[INFO] Completed!" + +Exit-Clean diff --git a/open-banking-accelerator/accelerators/ob-apim/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 b/open-banking-accelerator/accelerators/ob-apim/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 index 6e261320..ea4259db 100644 --- a/open-banking-accelerator/accelerators/ob-apim/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 +++ b/open-banking-accelerator/accelerators/ob-apim/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 @@ -1,6 +1,6 @@ diff --git a/open-banking-accelerator/accelerators/ob-apim/pom.xml b/open-banking-accelerator/accelerators/ob-apim/pom.xml index d5cb6c64..5dff7c99 100644 --- a/open-banking-accelerator/accelerators/ob-apim/pom.xml +++ b/open-banking-accelerator/accelerators/ob-apim/pom.xml @@ -23,9 +23,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml @@ -49,14 +49,10 @@ ${project.basedir}/carbon-home/repository/components/lib **/jjwt-0.9.1.jar - **/mysql-connector-java-5.1.44.jar ${project.basedir}/carbon-home/repository/components/dropins - - **/hazelcast-5.0.2.jar - ${project.basedir}/carbon-home/repository/deployment/server/webapps diff --git a/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/VRP-swagger.yaml b/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/VRP-swagger.yaml new file mode 100644 index 00000000..36d602e4 --- /dev/null +++ b/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/VRP-swagger.yaml @@ -0,0 +1,1573 @@ +openapi: 3.0.0 +info: + title: "VRPInitiationAPI" + description: "VRP OpenAPI Specification" + version: "v3.1" + +servers: + - url: "/open-banking/{version}/vrp" + +paths: + /domestic-vrp-consents: + post: + tags: + - "Domestic VRP Consents" + summary: Create a domestic VRP consent + description: Create a domestic VRP consent + parameters: + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + - $ref: "#/components/parameters/x-idempotency-key" + + responses: + '201': + $ref: "#/components/responses/20xOBDomesticVRPConsentResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + requestBody: + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentRequest" + application/json: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentRequest" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentRequest" + description: "Default" + required: true + security: + - TPPOAuth2Security: + - "payments" + - default: + - "payments" + x-auth-type: Application + x-throttling-tier: Unlimited + x-scope: payments + /domestic-vrp-consents/{ConsentId}: + get: + operationId: domesticVrpConsentsGet + tags: + - "Domestic VRP Consents" + summary: Retrieve a domestic VRP consent + description: Retrieve a domestic VRP consent + parameters: + - $ref: "#/components/parameters/ConsentId" + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + + responses: + '200': + $ref: "#/components/responses/20xOBDomesticVRPConsentResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + security: + - TPPOAuth2Security: + - "payments" + - default: + - "payments" + x-auth-type: Application + x-throttling-tier: Unlimited + x-scope: payments + delete: + operationId: domesticVrpConsentsDelete + tags: + - "Domestic VRP Consents" + summary: Delete a domestic VRP + description: Delete a domestic VRP + parameters: + - $ref: "#/components/parameters/ConsentId" + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + + responses: + '204': + description: 'delete successful' + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + security: + - TPPOAuth2Security: + - "payments" + x-auth-type: Application + x-throttling-tier: Unlimited + x-scope: payments + /domestic-vrp-consents/{ConsentId}/funds-confirmation: + post: + tags: + - "Domestic VRP Consents" + summary: Confirm availability of funds for a VRP + description: Confirm availability of funds for a VRP + parameters: + - $ref: "#/components/parameters/ConsentId" + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + + responses: + '201': + $ref: "#/components/responses/201OBDomesticVRPFundsConfirmationResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + requestBody: + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationRequest" + application/json: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationRequest" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationRequest" + description: "Default" + required: true + security: + - PSUOAuth2Security: + - "payments" + x-auth-type: Application User + x-throttling-tier: Unlimited + x-scope: payments + /domestic-vrps: + post: + tags: + - "Domestic VRPs" + summary: Create a domestic VRP + description: Create a domestic VRP + parameters: + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + - $ref: "#/components/parameters/x-idempotency-key" + + responses: + '201': + $ref: "#/components/responses/20xOBDomesticVRPResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + requestBody: + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBDomesticVRPRequest" + application/json: + schema: + $ref: "#/components/schemas/OBDomesticVRPRequest" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBDomesticVRPRequest" + description: "Default" + required: true + security: + - PSUOAuth2Security: + - "payments" + x-auth-type: Application User + x-throttling-tier: Unlimited + x-scope: payments + /domestic-vrps/{DomesticVRPId}: + get: + tags: + - "Domestic VRPs" + summary: Retrieve a domestic VRP + description: Retrieve a domestic VRP + parameters: + - $ref: "#/components/parameters/DomesticVRPId" + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + + responses: + '200': + $ref: "#/components/responses/20xOBDomesticVRPResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + security: + - TPPOAuth2Security: + - "payments" + x-auth-type: Application + x-throttling-tier: Unlimited + x-scope: payments + /domestic-vrps/{DomesticVRPId}/payment-details: + get: + tags: + - "Domestic VRPs" + summary: Retrieve a domestic VRP + description: Retrieve a domestic VRP + parameters: + - $ref: "#/components/parameters/DomesticVRPId" + - $ref: "#/components/parameters/x-fapi-auth-date" + - $ref: "#/components/parameters/x-fapi-customer-ip-address" + - $ref: "#/components/parameters/x-fapi-interaction-id" + - $ref: "#/components/parameters/Authorization" + + responses: + '200': + $ref: "#/components/responses/20xOBDomesticVRPRequestDetailResponse" + '400': + $ref: "#/components/responses/400Error" + '401': + $ref: "#/components/responses/401Error" + '403': + $ref: "#/components/responses/403Error" + '405': + $ref: "#/components/responses/405Error" + '406': + $ref: "#/components/responses/406Error" + '415': + $ref: "#/components/responses/415Error" + '429': + $ref: "#/components/responses/429Error" + '500': + $ref: "#/components/responses/500Error" + security: + - TPPOAuth2Security: + - "payments" + x-auth-type: Application + x-throttling-tier: Unlimited + x-scope: payments +components: + responses: + 400Error: + description: "Bad request" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/json: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + 401Error: + description: "Unauthorized" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 403Error: + description: "Forbidden" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/json: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + 404Error: + description: "Not found" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 405Error: + description: "Method Not Allowed" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 406Error: + description: "Not Acceptable" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 415Error: + description: "Unsupported Media Type" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 429Error: + description: "Too Many Requests" + headers: + Retry-After: + description: "Number in seconds to wait" + schema: + type: "integer" + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + 500Error: + description: "Internal Server Error" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + x-jws-signature: + description: "Header containing a detached JWS signature of the body of the payload." + required: true + schema: + type: "string" + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/json: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBErrorResponse1" + 20xOBDomesticVRPConsentResponse: + description: "Default response" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentResponse" + application/json: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentResponse" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBDomesticVRPConsentResponse" + 201OBDomesticVRPFundsConfirmationResponse: + description: "Default response" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationResponse" + application/json: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationResponse" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBVRPFundsConfirmationResponse" + 20xOBDomesticVRPResponse: + description: "Default response" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBDomesticVRPResponse" + application/json: + schema: + $ref: "#/components/schemas/OBDomesticVRPResponse" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBDomesticVRPResponse" + 20xOBDomesticVRPRequestDetailResponse: + description: "Default response" + headers: + x-fapi-interaction-id: + description: "An RFC4122 UID used as a correlation id." + required: true + schema: + type: "string" + + content: + application/json; charset=utf-8: + schema: + $ref: "#/components/schemas/OBDomesticVRPDetails" + application/json: + schema: + $ref: "#/components/schemas/OBDomesticVRPDetails" + application/jose+jwe: + schema: + $ref: "#/components/schemas/OBDomesticVRPDetails" + parameters: + ConsentId: + name: "ConsentId" + in: "path" + description: "ConsentId" + required: true + schema: + type: "string" + DomesticVRPId: + name: "DomesticVRPId" + in: "path" + description: "DomesticVRPId" + required: true + schema: + type: "string" + Authorization: + in: "header" + name: "Authorization" + required: true + description: "An Authorisation Token as per https://tools.ietf.org/html/rfc6750" + schema: + type: "string" + x-fapi-customer-ip-address: + in: "header" + name: "x-fapi-customer-ip-address" + required: false + description: "The PSU's IP address if the PSU is currently logged in with the TPP." + schema: + type: "string" + x-fapi-auth-date: + in: "header" + name: "x-fapi-auth-date" + required: false + description: "The time when the PSU last logged in with the TPP. \nAll dates in the HTTP headers are represented as RFC 7231 Full Dates. An example is below: \nSun, 10 Sep 2017 19:43:31 UTC" + schema: + type: "string" + pattern: "^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), \\d{2} (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d{4} \\d{2}:\\d{2}:\\d{2} (GMT|UTC)$" + x-fapi-interaction-id: + in: "header" + name: "x-fapi-interaction-id" + required: false + description: "An RFC4122 UID used as a correlation id." + schema: + type: "string" + x-idempotency-key: + name: "x-idempotency-key" + in: "header" + description: "Every request will be processed only once per x-idempotency-key. The\nIdempotency Key will be valid for 24 hours.\n" + required: true + schema: + type: "string" + maxLength: 40 + pattern: "^(?!\\s)(.*)(\\S)$" + + schemas: + OBError1: + type: "object" + additionalProperties: false + properties: + ErrorCode: + description: "Low level textual error code, e.g., OB.Field.Missing" + type: "string" + x-namespaced-enum: + - "OB.Field.Expected" + - "OB.Field.Invalid" + - "OB.Field.InvalidDate" + - "OB.Field.Missing" + - "OB.Field.Unexpected" + - "OB.Header.Invalid" + - "OB.Header.Missing" + - "OB.Reauthenticate" + - "OB.Resource.ConsentMismatch" + - "OB.Resource.InvalidConsentStatus" + - "OB.Resource.InvalidFormat" + - "OB.Resource.NotFound" + - "OB.Rules.AfterCutOffDateTime" + - "OB.Rules.DuplicateReference" + - "OB.Rules.FailsControlParameters" + - "OB.Signature.Invalid" + - "OB.Signature.InvalidClaim" + - "OB.Signature.Malformed" + - "OB.Signature.Missing" + - "OB.Signature.MissingClaim" + - "OB.Signature.Unexpected" + - "OB.UnexpectedError" + - "OB.Unsupported.AccountIdentifier" + - "OB.Unsupported.AccountSecondaryIdentifier" + - "OB.Unsupported.Currency" + - "OB.Unsupported.Frequency" + - "OB.Unsupported.LocalInstrument" + - "OB.Unsupported.Scheme" + Message: + description: "A description of the error that occurred. e.g., 'A mandatory field isn't supplied' or 'RequestedExecutionDateTime must be in future'\nOBIE doesn't standardise this field" + type: "string" + minLength: 1 + maxLength: 500 + Path: + description: "Recommended but optional reference to the JSON Path of the field with error, e.g., Data.Initiation.InstructedAmount.Currency" + type: "string" + minLength: 1 + maxLength: 500 + Url: + description: "URL to help remediate the problem, or provide more information, or to API Reference, or help etc" + type: "string" + required: + - "ErrorCode" + - "Message" + minProperties: 1 + OBErrorResponse1: + description: "An array of detail error codes, and messages, and URLs to documentation to help remediation." + type: "object" + additionalProperties: false + properties: + Code: + description: "High level textual error code, to help categorize the errors." + type: "string" + minLength: 1 + maxLength: 40 + Id: + description: "A unique reference for the error instance, for audit purposes, in case of unknown/unclassified errors." + type: "string" + minLength: 1 + maxLength: 40 + Message: + description: "Brief Error message, e.g., 'There is something wrong with the request parameters provided'" + type: "string" + minLength: 1 + maxLength: 500 + Errors: + items: + $ref: "#/components/schemas/OBError1" + type: "array" + minItems: 1 + required: + - "Code" + - "Message" + - "Errors" + OBDomesticVRPConsentResponse: + type: object + required: + - Data + - Risk + - Links + - Meta + properties: + Data: + type: object + required: + - ConsentId + - CreationDateTime + - Status + - StatusUpdateDateTime + - ControlParameters + - Initiation + properties: + ReadRefundAccount: + type: string + enum: + - Yes + - No + description: > + Indicates whether information about RefundAccount should be included in the payment response. + ConsentId: + type: string + minLength: 1 + maxLength: 128 + description: > + Unique identification as assigned by the ASPSP to uniquely identify the consent resource. + CreationDateTime: + type: string + format: date-time + description: > + Date and time at which the resource was created. + Status: + type: string + description: > + Specifies the status of resource in code form. + enum: + - Authorised + - AwaitingAuthorisation + - Rejected + - Revoked + - Expired + StatusUpdateDateTime: + type: string + format: date-time + description: > + Date and time at which the resource status was updated. + ControlParameters: + $ref: '#/components/schemas/OBDomesticVRPControlParameters' + Initiation: + $ref: '#/components/schemas/OBDomesticVRPInitiation' + DebtorAccount: + description: The value must be populated for GET responses once the consent is approved. + $ref: '#/components/schemas/OBCashAccountDebtorWithName' + Risk: + $ref: '#/components/schemas/OBRisk1' + Links: + $ref: '#/components/schemas/Links' + Meta: + $ref: '#/components/schemas/Meta' + OBDomesticVRPConsentRequest: + type: object + required: + - Data + - Risk + properties: + Data: + type: object + required: + - ControlParameters + - Initiation + properties: + ReadRefundAccount: + type: string + enum: + - Yes + - No + description: > + Indicates whether information about RefundAccount should be included in the payment response. + ControlParameters: + $ref: '#/components/schemas/OBDomesticVRPControlParameters' + Initiation: + $ref: '#/components/schemas/OBDomesticVRPInitiation' + Risk: + $ref: '#/components/schemas/OBRisk1' + OBDomesticVRPControlParameters: + type: object + properties: + ValidFromDateTime: + type: string + format: date-time + description: ^ + Start date time for which the consent remains valid. + ValidToDateTime: + type: string + format: date-time + description: ^ + End date time for which the consent remains valid. + MaximumIndividualAmount: + $ref: '#/components/schemas/OBActiveOrHistoricCurrencyAndAmount' + PeriodicLimits: + type: array + items: + type: object + required: + - PeriodType + - PeriodAlignment + - Amount + - Currency + properties: + PeriodType: + type: string + enum: + - Day + - Week + - Fortnight + - Month + - Half-year + - Year + description: ^ + Period type for this period limit + PeriodAlignment: + type: string + enum: + - Consent + - Calendar + description: ^ + Specifies whether the period starts on the date of consent creation or lines up with a calendar + Amount: + $ref: '#/components/schemas/OBActiveCurrencyAndAmount_SimpleType' + Currency: + $ref: '#/components/schemas/ActiveOrHistoricCurrencyCode' + VRPType: + type: array + items: + $ref: '#/components/schemas/OBVRPConsentType' + minItems: 1 + description: ^ + The types of payments that can be made under this VRP consent. This can be used to indicate whether this include sweeping payment or other ecommerce payments. + PSUAuthenticationMethods: + type: array + items: + $ref: '#/components/schemas/OBVRPAuthenticationMethods' + minItems: 1 + description: ^ + Indicates that the PSU authentication methods supported. + SupplementaryData: + type: object + description: ^ + Additional information that can not be captured in the structured fields and/or any other specific block + OBDomesticVRPInitiation: + type: object + properties: + DebtorAccount: + $ref: '#/components/schemas/OBCashAccountDebtorWithName' + CreditorAgent: + $ref: '#/components/schemas/OBBranchAndFinancialInstitutionIdentification6' + CreditorAccount: + $ref: '#/components/schemas/OBCashAccountCreditor3' + RemittanceInformation: + type: object + description: ^ + Information supplied to enable the matching of an entry with the items that the transfer is intended to settle, such as commercial invoices in an accounts' receivable system. + properties: + Unstructured: + type: string + minLength: 1 + maxLength: 140 + description: ^ + Information supplied to enable the matching/reconciliation of an entry with the items that the payment is intended to settle, such as commercial invoices in an accounts' receivable system, in an unstructured form. + Reference: + type: string + minLength: 1 + maxLength: 35 + description : ^ + Unique reference, as assigned by the creditor, + to unambiguously refer to the payment transaction. + Usage - If available, the initiating party should provide this reference in the structured remittance information, to enable reconciliation by the creditor upon receipt of the amount of money. If the business context requires the use of a creditor reference or a payment remit identification, and only one identifier can be passed through the end-to-end chain, the creditor's reference or payment remittance identification should be quoted in the end-to-end transaction identification. + OBCashAccountDebtorWithName: + type: object + required: + - SchemeName + - Identification + - Name + properties: + SchemeName: + $ref: '#/components/schemas/OBExternalAccountIdentification4Code' + Identification: + type: string + minLength: 1 + maxLength: 256 + description: ^ + Identification assigned by an institution to identify an account. This identification is known by the account owner. + Name: + type: string + minLength: 1 + maxLength: 350 + description: ^ + Name of the account, as assigned by the account servicing institution. Usage The account name is the name or names of the account owner(s) represented at an account level. The account name is not the product name or the nickname of the account. + SecondaryIdentification: + type: string + minLength: 1 + maxLength: 34 + description: ^ + This is secondary identification of the account, as assigned by the account servicing institution. This can be used by building societies to additionally identify accounts with a roll number (in addition to a sort code and account number combination) + OBCashAccountCreditor3: + type: object + required: + - SchemeName + - Identification + - Name + properties: + SchemeName: + $ref: '#/components/schemas/OBExternalAccountIdentification4Code' + description: |- + Name of the identification scheme, in a coded form as published in an external list. + Identification: + type: string + minLength: 1 + maxLength: 256 + description: |- + Identification assigned by an institution to identify an account. This identification is known by the account owner. + Name: + type: string + minLength: 1 + maxLength: 350 + description: |- + Name of the account, as assigned by the account servicing institution. + Usage: the account name is the name or names of the account owner(s) represented at an account level. + The account name is not the product name or the nickname of the account. + SecondaryIdentification: + type: string + minLength: 1 + maxLength: 34 + description: |- + This is secondary identification of the account, as assigned by the account servicing institution. + This can be used by building societies to additionally identify accounts with a roll number (in addition to a sort code and account number combination) + OBBranchAndFinancialInstitutionIdentification6: + type: object + properties: + SchemeName: + $ref: '#/components/schemas/OBExternalFinancialInstitutionIdentification4Code' + Identification: + type: string + minLength: 1 + maxLength: 35 + description: ^ + Unique and unambiguous identification of a financial institution or a branch of a financial institution. + Name: + type: string + minLength: 1 + maxLength: 140 + description: ^ + Name by which an agent is known and which is usually used to identify that agent. + PostalAddress: + $ref: "#/components/schemas/OBPostalAddress6" + + OBDomesticVRPRequest: + type: object + required: + - Data + - Risk + properties: + Data: + type: object + required: + - ConsentId + - PSUAuthenticationMethod + - Initiation + - Instruction + properties: + ConsentId: + type: string + minLength: 1 + maxLength: 128 + description: |- + Identifier for the Domestic VRP Consent that this payment is made under. + PSUAuthenticationMethod: + allOf: + - $ref: '#/components/schemas/OBVRPAuthenticationMethods' + - description: The authentication method that was used to authenticate the PSU. + Initiation: + $ref: '#/components/schemas/OBDomesticVRPInitiation' + Instruction: + $ref: '#/components/schemas/OBDomesticVRPInstruction' + Risk: + $ref: '#/components/schemas/OBRisk1' + OBDomesticVRPResponse: + type: object + required: + - Data + - Risk + - Links + - Meta + properties: + Data: + type: object + required: + - DomesticVRPId + - ConsentId + - CreationDateTime + - Status + - StatusUpdateDateTime + - Initiation + - Instruction + properties: + DomesticVRPId: + type: string + minLength: 1 + maxLength: 40 + description: > + Unique identification as assigned by the ASPSP to uniquely identify the domestic payment resource. + ConsentId: + type: string + minLength: 1 + maxLength: 128 + description: > + Identifier for the Domestic VRP Consent that this payment is made under. + CreationDateTime: + type: string + format: date-time + description: > + Date and time at which the resource was created. + Status: + type: string + description: Specifies the status of the payment information group. + enum: + - AcceptedCreditSettlementCompleted + - AcceptedWithoutPosting + - AcceptedSettlementCompleted + - AcceptedSettlementInProcess + - Pending + - Rejected + StatusUpdateDateTime: + type: string + format: date-time + description: > + Date and time at which the resource status was updated. + ExpectedExecutionDateTime: + type: string + format: date-time + description: > + Expected execution date and time for the payment resource. + ExpectedSettlementDateTime: + type: string + format: date-time + description: > + Expected settlement date and time for the payment resource. + Refund: + $ref: '#/components/schemas/OBCashAccountDebtorWithName' + description: > + Only included in the response if `Data.ReadRefundAccount` is set to `Yes` in the consent. + Charges: + type: array + items: + required: + - Amount + - ChargeBearer + - Type + type: object + properties: + ChargeBearer: + $ref: '#/components/schemas/OBChargeBearerType1Code' + Type: + $ref: '#/components/schemas/OBExternalPaymentChargeType1Code' + Amount: + $ref: '#/components/schemas/OBActiveOrHistoricCurrencyAndAmount' + description: Set of elements used to provide details of a charge for + the payment initiation. + Initiation: + $ref: '#/components/schemas/OBDomesticVRPInitiation' + Instruction: + $ref: '#/components/schemas/OBDomesticVRPInstruction' + DebtorAccount: + $ref: '#/components/schemas/OBCashAccountDebtorWithName' + Risk: + $ref: '#/components/schemas/OBRisk1' + Links: + $ref: '#/components/schemas/Links' + Meta: + $ref: '#/components/schemas/Meta' + OBDomesticVRPDetails: + type: object + properties: + Data: + type: object + properties: + PaymentStatus: + type: array + items: + required: + - PaymentTransactionId + - Status + - StatusUpdateDateTime + type: object + properties: + PaymentTransactionId: + type: string + minLength: 1 + maxLength: 210 + description: |- + Unique identifier for the transaction within an servicing institution. This identifier is both unique and immutable. + Status: + type: string + description: |- + Status of a transfer, as assigned by the transaction administrator. + enum: + - Accepted + - AcceptedCancellationRequest + - AcceptedCreditSettlementCompleted + - AcceptedCustomerProfile + - AcceptedFundsChecked + - AcceptedSettlementCompleted + - AcceptedSettlementInProcess + - AcceptedTechnicalValidation + - AcceptedWithChange + - AcceptedWithoutPosting + - Cancelled + - NoCancellationProcess + - PartiallyAcceptedCancellationRequest + - PartiallyAcceptedTechnicalCorrect + - PaymentCancelled + - Pending + - PendingCancellationRequest + - Received + - Rejected + - RejectedCancellationRequest + StatusUpdateDateTime: + type: string + format: date-time + description: > + Date and time at which the status was assigned to the transfer. + StatusDetail: + type: object + required: + - Status + properties: + LocalInstrument: + $ref: '#/components/schemas/OBExternalLocalInstrument1Code' + Status: + type: string + minLength: 1 + maxLength: 128 + description: |- + Status of a transfer, as assigned by the transaction administrator. + StatusReason: + type: string + description: |- + Reason Code provided for the status of a transfer. + enum: + - Cancelled + - PendingFailingSettlement + - PendingSettlement + - Proprietary + - ProprietaryRejection + - Suspended + - Unmatched + StatusReasonDescription: + type: string + minLength: 1 + maxLength: 128 + description: |- + Reason provided for the status of a transfer. + OBVRPFundsConfirmationRequest: + type: "object" + required: + - "Data" + description: |- + The OBVRPFundsConfirmationRequest object must be used to request funds availability for a specific amount in the Debtor Account included in the VRP consents. + properties: + Data: + type: "object" + required: + - ConsentId + - Reference + - InstructedAmount + properties: + FundsConfirmationId: + type: "string" + minLength: 1 + maxLength: 128 + description: |- + Unique identification as assigned by the ASPSP to uniquely identify the funds confirmation consent resource. + Reference: + type: string + minLength: 1 + maxLength: 35 + description: |- + Unique reference, as assigned by the PISP, to unambiguously refer to the request related to the payment transaction. + InstructedAmount: + $ref: '#/components/schemas/OBActiveOrHistoricCurrencyAndAmount' + OBVRPFundsConfirmationResponse: + type: "object" + description: |- + The confirmation of funds response contains the result of a funds availability check. + properties: + Data: + type: "object" + required: + - FundsConfirmationId + - ConsentId + - CreationDateTime + - Reference + - FundsAvailableResult + - InstructedAmount + properties: + FundsConfirmationId: + type: "string" + minLength: 1 + maxLength: 40 + description: |- + Unique identification as assigned by the ASPSP to uniquely identify the funds confirmation resource. + ConsentId: + type: "string" + minLength: 1 + maxLength: 128 + description: |- + Unique identification as assigned by the ASPSP to uniquely identify the funds confirmation consent resource. + CreationDateTime: + type: "string" + format: "date-time" + description: |- + Date and time at which the resource was created. + Reference: + type: "string" + minLength: 1 + maxLength: 35 + description: |- + Unique reference, as assigned by the CBPII, to unambiguously refer to the request related to the payment transaction. + FundsAvailableResult: + $ref: '#/components/schemas/OBPAFundsAvailableResult1' + description: "Flag to indicate the result of a confirmation of funds check." + type: "boolean" + InstructedAmount: + $ref: '#/components/schemas/OBActiveOrHistoricCurrencyAndAmount' + type: "object" + required: + - "Amount" + - "Currency" + description: "Amount of money to be confirmed as available funds in the debtor account. Contains an Amount and a Currency." + properties: + Amount: + description: "A number of monetary units specified in an active currency where the unit of currency is explicit and compliant with ISO 4217." + type: "string" + pattern: "^\\d{1,13}$|^\\d{1,13}\\.\\d{1,5}$" + Currency: + description: "A code allocated to a currency by a Maintenance Agency under an international identification scheme, as described in the latest edition of the international standard ISO 4217 \"Codes for the representation of currencies and funds\"." + type: "string" + pattern: "^[A-Z]{3,3}$" + OBPAFundsAvailableResult1: + type: object + description: |- + Availability result, clearly indicating the availability of funds given the Amount in the request. + required: + - FundsAvailableDateTime + - FundsAvailable + properties: + FundsAvailableDateTime: + type: string + format: date-time + description: |- + Date and time at which the funds availability check was generated. + FundsAvailable: + type: string + description: |- + Availability result, clearly indicating the availability of funds given the Amount in the request. + enum: + - Available + - NotAvailable + OBCharge2: + type: object + required: + - ChargeBearer + - Type + - Amount + properties: + ChargeBearer: + $ref: '#/components/schemas/OBChargeBearerType1Code' + OBExternalStatus2Code: + type: string + enum: + - Authorised + - AwaitingFurtherAuthorisation + - Rejected + OBChargeBearerType1Code: + type: string + description: |- + Specifies which party/parties will bear the charges associated with the processing of the payment transaction. + enum: + - BorneByCreditor + - BorneByDebtor + - FollowingServiceLevel + - Shared + OBDomesticVRPInstruction: + type: object + required: + - InstructionIdentification + - EndToEndIdentification + - CreditorAccount + properties: + InstructionIdentification: + type: string + minLength: 1 + maxLength: 35 + description: |- + Unique identification as assigned by an instructing party for an instructed party to unambiguously identify the instruction. + Usage: the instruction identification is a point to point reference that can be used between the instructing party and the instructed party to refer to the individual instruction. + It can be included in several messages related to the instruction. + EndToEndIdentification: + type: string + minLength: 1 + maxLength: 35 + description: |- + Unique identification assigned by the initiating party to unambiguously identify the transaction. + This identification is passed on, unchanged, throughout the entire end-to-end chain. + Usage: The end-to-end identification can be used for reconciliation or to link tasks relating to the transaction. + It can be included in several messages related to the transaction. + OB: The Faster Payments Scheme can only access 31 characters for the EndToEndIdentification field + RemittanceInformation: + $ref: '#/components/schemas/OBVRPRemittanceInformation' + LocalInstrument: + $ref: '#/components/schemas/OBExternalLocalInstrument1Code' + InstructedAmount: + $ref: '#/components/schemas/OBActiveOrHistoricCurrencyAndAmount' + CreditorAgent: + $ref: '#/components/schemas/OBBranchAndFinancialInstitutionIdentification6' + CreditorAccount: + $ref: '#/components/schemas/OBCashAccountCreditor3' + SupplementaryData: + type: object + description: > + Additional information that can not be captured in the structured fields and/or any other specific block. + OBVRPRemittanceInformation: + type: object + description: |- + Information supplied to enable the matching of an entry with the items that the transfer is intended to settle, such as commercial invoices in an accounts' receivable system. + properties: + Unstructured: + type: string + minLength: 1 + maxLength: 140 + description: |- + Information supplied to enable the matching/reconciliation of an entry with the items that the payment is intended to settle, such as commercial invoices in an accounts' receivable system, in an unstructured form. + Reference: + type: string + minLength: 1 + maxLength: 35 + description: |- + Unique reference, as assigned by the creditor, to unambiguously refer to the payment transaction. The PISP must populate this with the same value as specified in the `Data.Initiation.RemittanceInformation.Reference` of the consent. + OBExternalAccountIdentification4Code: + type: string + description: |- + Name of the identification scheme, in a coded form as published in an external list. + x-namespaced-enum: + - OB.BBAN + - OB.IBAN + - OB.PAN + - OB.Paym + - OB.SortCodeAccountNumber + OBExternalFinancialInstitutionIdentification4Code: + description: |- + Name of the identification scheme, in a coded form as published in an external list. + type: string + x-namespaced-enum: + - "OB.BICFI" + OBExternalLocalInstrument1Code: + type: string + description: |- + User community specific instrument. + Usage: This element is used to specify a local instrument, local clearing option and/or further qualify the service or service level. + x-namespaced-enum: + - OB.BACS + - OB.BalanceTransfer + - OB.CHAPS + - OB.Euro1 + - OB.FPS + - OB.Link + - OB.MoneyTransfer + - OB.Paym + - OB.SEPACreditTransfer + - OB.SEPAInstantCreditTransfer + - OB.SWIFT + - OB.Target2 + OBActiveOrHistoricCurrencyAndAmount: + required: + - Amount + - Currency + type: object + properties: + Amount: + $ref: '#/components/schemas/OBActiveCurrencyAndAmount_SimpleType' + Currency: + $ref: '#/components/schemas/ActiveOrHistoricCurrencyCode' + ActiveOrHistoricCurrencyCode: + type: string + minLength: 3 + maxLength: 3 + pattern: ^[A-Z]{3,3}$ + description: A code allocated to a currency by a Maintenance Agency under an + international identification scheme, as described in the latest edition of + the international standard ISO 4217 "Codes for the representation of currencies + and funds". + OBActiveCurrencyAndAmount_SimpleType: + pattern: ^\d{1,13}$|^\d{1,13}\.\d{1,5}$ + type: string + description: A number of monetary units specified in an active currency where + the unit of currency is explicit and compliant with ISO 4217. + OBExternalPaymentChargeType1Code: + type: string + enum: + - OB.CHAPSOut + - OB.BalanceTransferOut + - OB.MoneyTransferOut + OBPostalAddress6: + type: object + additionalProperties: false + description: Information that locates and identifies a specific address, as defined by postal services. + properties: + AddressType: + $ref: "#/components/schemas/OBAddressTypeCode" + Department: + $ref: "#/components/schemas/Department" + SubDepartment: + $ref: "#/components/schemas/SubDepartment" + StreetName: + $ref: "#/components/schemas/StreetName" + BuildingNumber: + $ref: "#/components/schemas/BuildingNumber" + PostCode: + $ref: "#/components/schemas/PostCode" + TownName: + $ref: "#/components/schemas/TownName" + CountrySubDivision: + $ref: "#/components/schemas/CountrySubDivision" + Country: + $ref: "#/components/schemas/CountryCode" + AddressLine: + type: array + items: + description: |- + Information that locates and identifies a specific address, as defined by postal services, presented in free format text. + type: "string" + minLength: 1 + maxLength: 70 + minItems: 0 + maxItems: 7 + OBAddressTypeCode: + description: Identifies the nature of the postal address. + type: string + enum: + - Business + - Correspondence + - DeliveryTo + - MailTo + - POBox + - Postal + - Residential + - Statement + Department: + description: Identification of a division of a large organisation or building. + type: string + minLength: 1 + maxLength: 70 + SubDepartment: + description: Identification of a sub-division of a large organisation or building. + type: string + minLength: 1 + maxLength: 70 + StreetName: + type: string + minLength: 1 + maxLength: 70 + description: Name of a street or thoroughfare. + BuildingNumber: + type: string + minLength: 1 + maxLength: 16 + description: Number that identifies the position of a building on a street. + PostCode: + type: string + minLength: 1 + maxLength: 16 + description: Identifier consisting of a group of letters and/or numbers that + is added to a postal address to assist the sorting of mail. + TownName: + type: string + minLength: 1 + maxLength: 35 + description: Name of a built-up area, with defined boundaries, and a local government. + CountrySubDivision: + type: string + minLength: 1 + maxLength: 35 + description: Identifies a subdivision of a country such as state, region, county. + CountryCode: + type: string + pattern: "^[A-Z]{2,2}$" + description: Nation with its own government. + OBVRPConsentType: + type: string + x-namespaced-enum: + - OB.VRPType.Sweeping + - OB.VRPType.Other + OBVRPAuthenticationMethods: + type: string + x-namespaced-enum: + - OB.SCA + - OB.SCANotRequired + OBRisk1: + type: object + properties: + PaymentContextCode: + type: string + description: Specifies the payment context + enum: + - BillPayment + - EcommerceGoods + - EcommerceServices + - Other + - PartyToParty + MerchantCategoryCode: + type: string + minLength: 3 + maxLength: 4 + description: Category code conform to ISO 18245, related to the type of + services or goods the merchant provides for the transaction. + MerchantCustomerIdentification: + type: string + minLength: 1 + maxLength: 70 + description: The unique customer identifier of the PSU with the merchant. + DeliveryAddress: + required: + - Country + - TownName + type: object + properties: + AddressLine: + maxItems: 2 + minItems: 0 + type: array + items: + type: string + minLength: 1 + maxLength: 70 + description: |- + Information that locates and identifies a specific address, + as defined by postal services, that is presented in free format + text. + StreetName: + $ref: '#/components/schemas/StreetName' + BuildingNumber: + $ref: '#/components/schemas/BuildingNumber' + PostCode: + $ref: '#/components/schemas/PostCode' + TownName: + $ref: '#/components/schemas/TownName' + CountrySubDivision: + $ref: '#/components/schemas/CountrySubDivision' + Country: + $ref: '#/components/schemas/CountryCode' + description: |- + Information that locates and identifies a specific address, + as defined by postal services or in free format text. + description: |- + The Risk section is sent by the initiating party to the ASPSP. + It is used to specify additional details for risk scoring for Payments. + Links: + required: + - Self + type: object + properties: + Self: + type: string + format: uri + First: + type: string + format: uri + Prev: + type: string + format: uri + Next: + type: string + format: uri + Last: + type: string + format: uri + description: Links relevant to the payload + Meta: + title: MetaData + type: object + description: Meta Data relevant to the payload. At present no fields are used for VRP. + securitySchemes: + TPPOAuth2Security: + type: "oauth2" + description: "TPP client credential authorisation flow with the ASPSP" + flows: + clientCredentials: + tokenUrl: "https://authserver.example/token" + scopes: + payments: "Generic payment scope" + + PSUOAuth2Security: + type: "oauth2" + description: "OAuth flow, it is required when the PSU needs to perform SCA with the ASPSP when a TPP wants to access an ASPSP resource owned by the PSU" + flows: + authorizationCode: + authorizationUrl: "https://authserver.example/authorization" + tokenUrl: "https://authserver.example/token" + scopes: + payments: "Generic payment scope" + + default: + type: "oauth2" + flows: + implicit: + authorizationUrl: "https://test.com" + scopes: + payments: "Generic payment scope" + x-scopes-bindings: + payments: "Internal/subscriber" \ No newline at end of file diff --git a/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/vrp-dynamic-endpoint-insequence-3.1.9.xml b/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/vrp-dynamic-endpoint-insequence-3.1.9.xml new file mode 100644 index 00000000..e98ffd87 --- /dev/null +++ b/open-banking-accelerator/accelerators/ob-apim/repository/resources/apis/VRP/vrp-dynamic-endpoint-insequence-3.1.9.xml @@ -0,0 +1,32 @@ + + + + + +
+ + +
+
+ + +
+ + + \ No newline at end of file diff --git a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.0.0-deployment.toml b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.0.0-deployment.toml index dc1e2509..29ae8ffc 100644 --- a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.0.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.0.0-deployment.toml @@ -431,6 +431,12 @@ roles = "AISP,PISP" api_name = "AccountandTransactionAPI" roles = "AISP" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #============executors========================= [[open_banking.gateway.openbanking_gateway_executors.type]] name = "Default" @@ -471,6 +477,9 @@ priority = 1000 [open_banking.apim.analytics] enable=false +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.1.0-deployment.toml b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.1.0-deployment.toml index 5418fc2e..4264444a 100644 --- a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.1.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.1.0-deployment.toml @@ -431,6 +431,12 @@ roles = "AISP,PISP" api_name = "AccountandTransactionAPI" roles = "AISP" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #============executors========================= [[open_banking.gateway.openbanking_gateway_executors.type]] name = "Default" @@ -471,6 +477,9 @@ priority = 1000 [open_banking.apim.analytics] enable=false +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.2.0-deployment.toml b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.2.0-deployment.toml index 6e7a23c2..13f005ff 100644 --- a/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.2.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-apim/repository/resources/wso2am-4.2.0-deployment.toml @@ -435,6 +435,12 @@ roles = "AISP,PISP" api_name = "AccountandTransactionAPI" roles = "AISP" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #============executors========================= [[open_banking.gateway.openbanking_gateway_executors.type]] name = "Default" @@ -475,6 +481,9 @@ priority = 1000 [open_banking.apim.analytics] enable=false +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/ob-bi/pom.xml b/open-banking-accelerator/accelerators/ob-bi/pom.xml index b7e41ee0..98bd09f8 100644 --- a/open-banking-accelerator/accelerators/ob-bi/pom.xml +++ b/open-banking-accelerator/accelerators/ob-bi/pom.xml @@ -23,9 +23,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml diff --git a/open-banking-accelerator/accelerators/ob-is/bin/configure.ps1 b/open-banking-accelerator/accelerators/ob-is/bin/configure.ps1 index 36eed1fb..fac979a0 100644 --- a/open-banking-accelerator/accelerators/ob-is/bin/configure.ps1 +++ b/open-banking-accelerator/accelerators/ob-is/bin/configure.ps1 @@ -1,4 +1,4 @@ - # Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + # Copyright (c) 2023-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 @@ -14,139 +14,208 @@ # specific language governing permissions and limitations # under the License. -# command to execute -# ./configure.ps1 +# How to execute : +# If your accelerator is located inside of the base product you can just call .\configure.ps1 +# If your accelerator is in a different location you can call .\configure.ps1 + +# IMPORTANT : +# Please note that these powershell files are not digitally signed yet. So, powershell will not allow these scripts under any of their execution policies. +# You may need to run these scripts on an execution policy bypassed powershell instance. You can do that using the following command. +# powershell.exe -executionpolicy bypass + +# Get the current working directory of the powershell session, so we can set to this directory after the script finishes. +$CURRENT_DIRECTORY = (Get-Location).path + +# Some black magic to get the fully qualified path of the WSO2 Base Product if it was given as an argument. +$WSO2_BASE_PRODUCT_HOME = $args[0] +if (-NOT($null -eq $WSO2_BASE_PRODUCT_HOME)) { + if (Test-Path $WSO2_BASE_PRODUCT_HOME) { + Set-Location $WSO2_BASE_PRODUCT_HOME + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path + Set-Location $CURRENT_DIRECTORY + } +} +Function Exit-Clean { + Set-Location $CURRENT_DIRECTORY + exit 1 +} -$Props = convertfrom-stringdata (get-content ./../repository/conf/configure.properties -raw) -$WSO2_OB_IS_HOME = $args[0] +# A utility function to Find and Replace texts in a file. +Function Find-Replace { + param( + [string]$FILE_PATH, + [string]$OLD_TEXT, + [string]$NEW_TEXT + ) -# set accelerator home -Set-Location ../ -$ACCELERATOR_HOME = $pwd.path -Write-Output "Accelerator Home: $ACCELERATOR_HOME" + # Read the file content + $CONTENT = Get-Content $FILE_PATH -Raw -# set product home -if ($null -eq $WSO2_OB_IS_HOME) -{ - Set-Location ../ - $WSO2_OB_IS_HOME = $pwd.path - Write-Output "Product Home: $WSO2_OB_IS_HOME" + # Escape special characters in OLD_TEXT for the regex + $escapedOldText = [regex]::Escape($OLD_TEXT) + + # Define the regex pattern to consider non-word characters as boundaries + $regex = "(?// +Set-Location (Join-Path $PSScriptRoot ".\..\") +$WSO2_OB_ACCELERATOR_HOME = (Get-Location).path +Write-Output "[INFO] Accelerator Home : $WSO2_OB_ACCELERATOR_HOME" + +# Get the root directory of the base product. +if ($null -eq $WSO2_BASE_PRODUCT_HOME) { + Set-Location (Join-Path $WSO2_OB_ACCELERATOR_HOME ".\..\") + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path } -else -{ - Write-Output "`nValid carbon product path.`n" +Write-Output "[INFO] Base Product Home : $WSO2_BASE_PRODUCT_HOME" + +# Check whether the extracted base product location contains a valid WSO2 carbon product by checking whether this location +# contains the "repository/components" directory. +if (-NOT(Test-Path (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components"))) { + Write-Output "[ERROR] $WSO2_BASE_PRODUCT_HOME does NOT contain a valid carbon product!" + # The current path does not contain a valid carbon product. + # Set the current working directory to the original location and exit. + Exit-Clean +} else { + Write-Output "[INFO] $WSO2_BASE_PRODUCT_HOME is a valid carbon product home." } -# read deployment.toml file -$DEPLOYMENT_TOML_FILE = "$ACCELERATOR_HOME/repository/resources/deployment.toml" -Copy-Item -Path "$ACCELERATOR_HOME/$( $Props.'PRODUCT_CONF_PATH' )" $DEPLOYMENT_TOML_FILE +# Get the location of the configure.properties +$CONFIG_PROPERTIES_PATH = Join-Path $WSO2_OB_ACCELERATOR_HOME "repository\conf\configure.properties" +Write-Output "[INFO] configure.properties location : $CONFIG_PROPERTIES_PATH" + +# Load the variables in the configure.properties file +$PROPERTIES = ConvertFrom-StringData (Get-Content $CONFIG_PROPERTIES_PATH -raw) + +$SELECTED_DEPLOYMENT_TOML_FILE = Join-Path $WSO2_OB_ACCELERATOR_HOME $PROPERTIES.'PRODUCT_CONF_PATH' +Write-Output "[INFO] Selected deployment.toml location : $SELECTED_DEPLOYMENT_TOML_FILE" -Function Configure-Datasources +$DEPLOYMENT_TOML_FILE = Join-Path $WSO2_OB_ACCELERATOR_HOME "repository\resources\deployment.toml" +# Temporary copy the selected toml file so we can make changes to it. +Copy-Item -Path $SELECTED_DEPLOYMENT_TOML_FILE $DEPLOYMENT_TOML_FILE +Write-Output "[INFO] Temporary deployment.toml location : $DEPLOYMENT_TOML_FILE" + +# A function to replace the database related variables in the temp deployment.toml with their actual values from configure.properties +Function Set-Datasources { - if ($Props.'DB_TYPE' -eq "mysql") + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { - # IS - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_APIMGT_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_APIMGT' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_IS_CONFIG_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_IS_CONFIG' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_GOV_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_GOV' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER_STORE_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_USER_STORE' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_OB_STORE_URL", "jdbc:mysql://$( $Props.'DB_HOST' ):3306/$( $Props.'DB_OPEN_BANKING_STORE' )?autoReconnect=true&useSSL=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER", "$( $Props.'DB_USER' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_PASS", "$( $Props.'DB_PASS' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_DRIVER", "$( $Props.'DB_DRIVER' )" }) + # MySQL + Find-Replace $DEPLOYMENT_TOML_FILE "DB_APIMGT_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_APIMGT' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_IS_CONFIG_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_IS_CONFIG' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_GOV_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_GOV' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER_STORE_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_USER_STORE' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_OB_STORE_URL" "jdbc:mysql://$( $PROPERTIES.'DB_HOST' ):3306/$( $PROPERTIES.'DB_OPEN_BANKING_STORE' )?allowPublicKeyRetrieval=true&autoReconnect=true&useSSL=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER" "$( $PROPERTIES.'DB_USER' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_PASS" "$( $PROPERTIES.'DB_PASS' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_DRIVER" "$( $PROPERTIES.'DB_DRIVER' )" } - else + elseif($PROPERTIES.'DB_TYPE' -eq "mssql") { - # IS - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_APIMGT_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_APIMGT' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_IS_CONFIG_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_IS_CONFIG' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_GOV_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_GOV' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER_STORE_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_USER_STORE' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_OB_STORE_URL", "jdbc:sqlserver://$( $Props.'DB_HOST' ):1433;databaseName=$( $Props.'DB_OPEN_BANKING_STORE' );encrypt=false" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_USER", "$( $Props.'DB_USER' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_PASS", "$( $Props.'DB_PASS' )" }) - Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "DB_DRIVER", "$( $Props.'DB_DRIVER' )" }) + # Microsoft SQL Server + Find-Replace $DEPLOYMENT_TOML_FILE "DB_APIMGT_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_APIMGT' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_IS_CONFIG_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_IS_CONFIG' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_GOV_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_GOV' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER_STORE_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_USER_STORE' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_OB_STORE_URL" "jdbc:sqlserver://$( $PROPERTIES.'DB_HOST' ):1433;databaseName=$( $PROPERTIES.'DB_OPEN_BANKING_STORE' );encrypt=false" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_USER" "$( $PROPERTIES.'DB_USER' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_PASS" "$( $PROPERTIES.'DB_PASS' )" + Find-Replace $DEPLOYMENT_TOML_FILE "DB_DRIVER" "$( $PROPERTIES.'DB_DRIVER' )" + } + else { + Write-Output "[ERROR] Unsupported Database Type!" + Exit-Clean } } -Function Create-Databases -{ - if ($Props.'DB_TYPE' -eq "mysql") - { - if ($Props.'DB_PASS' -eq "") - { - $DB_MYSQL_PASS = "" - } - else - { - $DB_MYSQL_PASS = $Props.'DB_PASS' +# A function to replace the hostname related variables in the temp deployment.toml with their actual values from configure.properties +Function Set-Hostnames { + Find-Replace $DEPLOYMENT_TOML_FILE "APIM_HOSTNAME" "$( $PROPERTIES.'APIM_HOSTNAME' )" + Find-Replace $DEPLOYMENT_TOML_FILE "IS_HOSTNAME" "$( $PROPERTIES.'IS_HOSTNAME' )" + Find-Replace $DEPLOYMENT_TOML_FILE "BI_HOSTNAME" "$( $PROPERTIES.'BI_HOSTNAME' )" +} + +# A utility function to create a database. +Function Add-Database { + param ([string]$DB_USER, [string]$DB_PASS, [string]$DB_HOST, [string]$DB_NAME) + mysql -u"$($DB_USER)" -p"$($DB_PASS)" -h"$($DB_HOST)" -e "DROP DATABASE IF EXISTS $($DB_NAME); CREATE DATABASE $( $DB_NAME ) DEFAULT CHARACTER SET latin1;" +} + +# A utility function to create a table inside a given database. +Function Add-TablesToDatabase { + param ([string]$DB_USER, [string]$DB_PASS, [string]$DB_HOST, [string]$DB_NAME, [string]$DB_SOURCE) + mysql -u"$($DB_USER)" -p"$($DB_PASS)" -h"$($DB_HOST)" -D"$($DB_NAME)" -e "SOURCE $($DB_SOURCE)" +} + +# A function to create the databases. ONLY SUPPORTED FOR THE MYSQL +Function Add-Databases { + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { + $DB_MYSQL_PASS = "" + if (-NOT($PROPERTIES.'DB_PASS' -eq "")) { + $DB_MYSQL_PASS = $PROPERTIES.'DB_PASS' } - Write-Output "`nCreating MySQL databases" - Write-Output "================================================`n" - Create-Mysql-Databases - Write-Output "`nCreate database tables" - Write-Output "================================================`n" - Create-Mysql-Database-Tables + Add-Database "$( $PROPERTIES.'DB_USER' )" "$DB_MYSQL_PASS" "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_IS_CONFIG' )" + Write-Output "Database Created: $( $PROPERTIES.'DB_IS_CONFIG' )" + + Add-Database "$( $PROPERTIES.'DB_USER' )" "$DB_MYSQL_PASS" "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_OPEN_BANKING_STORE' )" + Write-Output "Database Created: $( $PROPERTIES.'DB_OPEN_BANKING_STORE' )" } - else - { - Write-Output "`nAssume MSSQL/Oracle databases have already created manually" + else { + Write-Output "[INFO] The databases must be created manually for non mysql DBMSs." } } -Function Create-Mysql-Databases -{ - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_IS_CONFIG' ); CREATE DATABASE $( $Props.'DB_IS_CONFIG' ); ALTER DATABASE $( $Props.'DB_IS_CONFIG' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_IS_CONFIG' )" - mysql -u"$( $Props.'DB_USER' )" -p"$DB_MYSQL_PASS" -h"$( $Props.'DB_HOST' )" -e"DROP DATABASE IF EXISTS $( $Props.'DB_OPEN_BANKING_STORE' ); CREATE DATABASE $( $Props.'DB_OPEN_BANKING_STORE' ); ALTER DATABASE $( $Props.'DB_OPEN_BANKING_STORE' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci;" - Write-Output "Database Created: $( $Props.'DB_OPEN_BANKING_STORE' )" -} +# A function to create the database tables. ONLY SUPPORTED FOR THE MYSQL +Function Add-DatabaseTables { + if ($PROPERTIES.'DB_TYPE' -eq "mysql") { + $DB_MYSQL_PASS = "" + if (-NOT($PROPERTIES.'DB_PASS' -eq "")) { + $DB_MYSQL_PASS = $PROPERTIES.'DB_PASS' + } -Function Create-Mysql-Database-Tables -{ - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_IS_CONFIG' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_IS_HOME\dbscripts\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_IS_CONFIG' )" - cmd.exe /c "mysql -u$( $Props.'DB_USER' ) -p$DB_MYSQL_PASS -D$( $Props.'DB_OPEN_BANKING_STORE' ) -h$( $Props.'DB_HOST' ) < $WSO2_OB_IS_HOME\dbscripts\open-banking\consent\mysql.sql" - Write-Output "Database tables Created for: $( $Props.'DB_OPEN_BANKING_STORE' )" -} + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" "$DB_MYSQL_PASS" "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_IS_CONFIG' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\mysql.sql")" + Write-Output "Database tables Created for: $( $PROPERTIES.'DB_IS_CONFIG' )" -Function Configure-Iskm-Connector -{ - Invoke-WebRequest -Uri "https://apim.docs.wso2.com/en/4.0.0/assets/attachments/administer/$( $Props.'ISKM_CONNECTOR' ).zip" -OutFile ".\$( $Props.'ISKM_CONNECTOR' ).zip" - Expand-Archive -LiteralPath ".\$( $Props.'ISKM_CONNECTOR' ).zip" -DestinationPath ".\" - Copy-Item -Path "$( $Props.'ISKM_CONNECTOR_FOLDER' )/dropins/*" -Destination "$WSO2_OB_IS_HOME/repository/components/dropins/" -Recurse - Copy-Item -Path "$( $Props.'ISKM_CONNECTOR_FOLDER' )/webapps/*" -Destination "$WSO2_OB_IS_HOME/repository/deployment/server/webapps/" -Recurse + Add-TablesToDatabase "$( $PROPERTIES.'DB_USER' )" "$DB_MYSQL_PASS" "$( $PROPERTIES.'DB_HOST' )" "$( $PROPERTIES.'DB_OPEN_BANKING_STORE' )" "$(Join-Path $WSO2_BASE_PRODUCT_HOME "dbscripts\open-banking\consent\mysql.sql")" + Write-Output "Database tables Created for: $( $PROPERTIES.'DB_OPEN_BANKING_STORE' )" + } + else { + Write-Output "[INFO] The database tables must be created manually for non mysql DBMSs." + } } -Write-Output "`nReplace hostnames `n" -Write-Output "================================================`n" -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "IS_HOSTNAME", "$( $Props.'IS_HOSTNAME' )" }) -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "APIM_HOSTNAME", "$( $Props.'APIM_HOSTNAME' )" }) -Set-Content -Path $DEPLOYMENT_TOML_FILE -Value (get-content $DEPLOYMENT_TOML_FILE | ForEach-Object{ $_ -replace "BI_HOSTNAME", "$( $Props.'BI_HOSTNAME' )" }) +Write-Output "============================================" +Write-Output "[INFO] Configuring the hostnames..." +Set-Hostnames +Write-Output "[INFO] Hostnames configurations completed!" -Write-Output "`nConfigure datasources `n" -Write-Output "================================================`n" -Configure-Datasources +Write-Output "============================================" +Write-Output "[INFO] Configuring the datasources..." +Set-Datasources +Write-Output "[INFO] Datasources configurations completed!" -Write-Output "`nCreate databases" -Write-Output "================================================`n" -Create-Databases; +Write-Output "============================================" +Copy-Item $DEPLOYMENT_TOML_FILE (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\conf\deployment.toml") +Write-Output "[INFO] Copied temp toml to the $(Join-Path $WSO2_BASE_PRODUCT_HOME "repository\conf\deployment.toml")" -Write-Output "`nConfigure IS KM Connector" -Write-Output "================================================`n" -Configure-Iskm-Connector - -Write-Output "`nCopy deployment.toml file to repository/conf `n" -Write-Output "================================================`n" -Copy-Item $DEPLOYMENT_TOML_FILE $WSO2_OB_IS_HOME/repository/conf/ Remove-Item $DEPLOYMENT_TOML_FILE +Write-Output "[INFO] Deleted temp toml $DEPLOYMENT_TOML_FILE" + +Write-Output "============================================" +Add-Databases + +Write-Output "============================================" +Add-DatabaseTables + +Exit-Clean diff --git a/open-banking-accelerator/accelerators/ob-is/bin/merge.bat b/open-banking-accelerator/accelerators/ob-is/bin/merge.bat deleted file mode 100644 index 655dba41..00000000 --- a/open-banking-accelerator/accelerators/ob-is/bin/merge.bat +++ /dev/null @@ -1,54 +0,0 @@ - REM Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - REM - REM WSO2 LLC. licenses this file to you under the Apache License, - REM Version 2.0 (the "License"); you may not use this file except - REM in compliance with the License. - REM You may obtain a copy of the License at - REM - REM http://www.apache.org/licenses/LICENSE-2.0 - REM - REM Unless required by applicable law or agreed to in writing, - REM software distributed under the License is distributed on an - REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - REM KIND, either express or implied. See the License for the - REM specific language governing permissions and limitations - REM under the License. - -REM merge.bat script copy the WSO2 OB IS accelerator artifacts on top of WSO2 IS base product -REM -REM merge.bat - -@echo off - -SET IS_HOME=%1 - -REM set accelerator home -cd %CD%..\.. -SET OB_IS_ACCELERATOR_HOME=%CD% -echo "Accelerator home is: %OB_IS_ACCELERATOR_HOME%" - -REM set product home -if "%IS_HOME%" == "" ( - cd %CD%..\.. - SET IS_HOME=%CD% - echo "Product home is: %IS_HOME%" -) - -REM validate product home -if not exist %IS_HOME%\repository\components ( - echo "ERROR:specified product path is not a valid carbon product path" -) else ( - echo "Valid carbon product path." -) - -echo "Remove old open banking artifacts from base product" -del %IS_HOME%\repository\components\dropins\com.wso2.openbanking.* -del %IS_HOME%\repository\components\lib\com.wso2.openbanking.* - -echo "Copying open banking artifacts" -echo ================================================ -robocopy %OB_IS_ACCELERATOR_HOME%\carbon-home /e %IS_HOME% - - -DEL %IS_HOME%\repository\components\dropins\org.wso2.carbon.identity.application.authentication.handler.identifier-6.3.11.6.jar -echo "Complete!" diff --git a/open-banking-accelerator/accelerators/ob-is/bin/merge.ps1 b/open-banking-accelerator/accelerators/ob-is/bin/merge.ps1 new file mode 100644 index 00000000..a26a650c --- /dev/null +++ b/open-banking-accelerator/accelerators/ob-is/bin/merge.ps1 @@ -0,0 +1,125 @@ + # Copyright (c) 2023-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. + +# How to execute : +# If your accelerator is located inside of the base product you can just call .\merge.ps1 +# If your accelerator is in a different location you can call .\merge.ps1 + +# IMPORTANT : +# Please note that these powershell files are not digitally signed yet. So, powershell will not allow these scripts under any of their execution policies. +# You may need to run these scripts on an execution policy bypassed powershell instance. You can do that using the following command. +# powershell.exe -executionpolicy bypass + +# Get the current working directory of the powershell session, so we can set to this directory after the script finishes. +$CURRENT_DIRECTORY = (Get-Location).path + +# Some black magic to get the fully qualified path of the WSO2 Base Product if it was given as an argument. +$WSO2_BASE_PRODUCT_HOME = $args[0] +if (-NOT($null -eq $WSO2_BASE_PRODUCT_HOME)) { + if (Test-Path $WSO2_BASE_PRODUCT_HOME) { + Set-Location $WSO2_BASE_PRODUCT_HOME + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path + Set-Location $CURRENT_DIRECTORY + } +} + +Function Exit-Clean { + Set-Location $CURRENT_DIRECTORY + exit 1 +} + +# Get the root directory location of the accelerator. Which is // +Set-Location (Join-Path $PSScriptRoot ".\..\") +$WSO2_OB_ACCELERATOR_HOME = (Get-Location).path +Write-Output "[INFO] Accelerator Home : $WSO2_OB_ACCELERATOR_HOME" + +# Get the root directory of the base product. +if ($null -eq $WSO2_BASE_PRODUCT_HOME) { + Set-Location (Join-Path $WSO2_OB_ACCELERATOR_HOME ".\..\") + $WSO2_BASE_PRODUCT_HOME = (Get-Location).path +} +Write-Output "[INFO] Base Product Home : $WSO2_BASE_PRODUCT_HOME" + +# Check whether the extracted base product location contains a valid WSO2 carbon product by checking whether this location +# contains the "repository/components" directory. +if (-NOT(Test-Path (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components"))) { + Write-Error "[ERROR] $WSO2_BASE_PRODUCT_HOME does NOT contain a valid carbon product!" + # The current path does not contain a valid carbon product. + # Set the current working directory to the original location and exit. + Exit-Clean +} else { + Write-Output "[INFO] $WSO2_BASE_PRODUCT_HOME is a valid carbon product home." +} + +# Remove old open-banking artifacts +Write-Output "[INFO] Removing old open-banking artifacts..." +Get-ChildItem (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components\dropins") | Where-Object{$_.Name -Match "com.wso2.openbanking.accelerator.*"} | Remove-Item +Get-ChildItem (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components\lib") | Where-Object{$_.Name -Match "com.wso2.openbanking.accelerator.*"} | Remove-Item +Write-Output "[INFO] All previous OB artifacts have been deleted!" + +# Copying all the new OB artifacts to the base product +# Copy-Item -Force -Recurse -Verbose (Join-Path $WSO2_OB_ACCELERATOR_HOME "carbon-home\*") -Destination $WSO2_BASE_PRODUCT_HOME +# Using Robocopy.exe becuase powershell Copy-Item cmdlet doesn't do recursive copying after a certain number of subdirectories. +Write-Output "[INFO] Copying new open-banking artifacts..." +Robocopy.exe (Join-Path $WSO2_OB_ACCELERATOR_HOME "carbon-home") $WSO2_BASE_PRODUCT_HOME * /E /NFL /NDL /NJH /NJS /nc /ns /np +Write-Output "[INFO] All the new OB artifacts has been copied!" + +$WEB_APPS_PATH = (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\deployment\server\webapps") + +# Delete the consentmgr web app if it exists. +$CONSENTMGR_PATH = (Join-Path $WEB_APPS_PATH "consentmgr") +$CONSENTMGR_RUNTIME_JS_PATH = (Join-Path $CONSENTMGR_PATH "runtime-config.js") +$CONSENTMGR_RUNTIME_JS_BACKUP_PATH = (Join-Path $WEB_APPS_PATH "runtime-config.js") +if (Test-Path $CONSENTMGR_PATH) { + Write-Output "[INFO] consentmgr web app detected at `"$CONSENTMGR_PATH`"" + + if (Test-Path $CONSENTMGR_RUNTIME_JS_PATH -PathType Leaf) { + # If the consentmgr/runtime-config,js file exists, backup it to the webapps directory before deleting the directory + Write-Output "[INFO] Copying $CONSENTMGR_RUNTIME_JS_PATH to $CONSENTMGR_RUNTIME_JS_BACKUP_PATH..." + Copy-Item $CONSENTMGR_RUNTIME_JS_PATH -Destination $CONSENTMGR_RUNTIME_JS_BACKUP_PATH -Force + } + + Write-Output "[INFO] Deleting the current consentmgr web app..." + Remove-Item -LiteralPath $CONSENTMGR_PATH -Force -Recurse + Write-Output "[INFO] Deleted the current consentmgr web app!" +} + +$CONSENTMGR_PATH_WAR = (Join-Path $WEB_APPS_PATH "consentmgr.war") +$CONSENTMGR_PATH_ZIP = (Join-Path $WEB_APPS_PATH "consentmgr.zip") + +# Expand-Archive cmdlet cannot directly extract the .war files. Since .war files are just zip files with some custom file headers and a fancy extension +# we can just rename the war file and extract it. +Move-Item -Path $CONSENTMGR_PATH_WAR -Destination $CONSENTMGR_PATH_ZIP -Force + +# Extract the consentmgr.zip +Write-Output "[INFO] Extracting the new consentmgr..." +Expand-Archive -LiteralPath $CONSENTMGR_PATH_ZIP -DestinationPath $CONSENTMGR_PATH -Force +Write-Output "[INFO] New consentmgr extracted!" + +if (Test-Path $CONSENTMGR_RUNTIME_JS_BACKUP_PATH -PathType Leaf) { + # Copy back the backed up runtime-config.js + Write-Output "[INFO] Copying $CONSENTMGR_RUNTIME_JS_BACKUP_PATH to $CONSENTMGR_RUNTIME_JS_PATH..." + Copy-Item $CONSENTMGR_RUNTIME_JS_BACKUP_PATH -Destination $CONSENTMGR_RUNTIME_JS_PATH -Force + Remove-Item -LiteralPath $CONSENTMGR_RUNTIME_JS_BACKUP_PATH -Force +} + +Remove-Item -LiteralPath $CONSENTMGR_PATH_ZIP -Force + +Get-ChildItem (Join-Path $WSO2_BASE_PRODUCT_HOME "repository\components\dropins") | Where-Object{$_.Name -Match "org.wso2.carbon.identity.application.authentication.handler.identifier-*"} | Remove-Item + +Write-Output "[INFO] Completed!" + +Exit-Clean diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mssql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mssql.sql index a3fe7d61..6a9e59ad 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mssql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mssql.sql @@ -78,7 +78,7 @@ CREATE TABLE OB_CONSENT_FILE ( CREATE TABLE OB_CONSENT_ATTRIBUTE ( CONSENT_ID VARCHAR(255) NOT NULL, ATT_KEY VARCHAR(255) NOT NULL, - ATT_VALUE VARCHAR(255) NOT NULL, + ATT_VALUE VARCHAR(1023) NOT NULL, PRIMARY KEY(CONSENT_ID, ATT_KEY), CONSTRAINT FK_OB_CONSENT_ATTRIBUTE FOREIGN KEY (CONSENT_ID) REFERENCES OB_CONSENT (CONSENT_ID) ON DELETE CASCADE ); diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mysql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mysql.sql index 56d96860..f6cda887 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mysql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/mysql.sql @@ -82,7 +82,7 @@ ENGINE INNODB; CREATE TABLE IF NOT EXISTS OB_CONSENT_ATTRIBUTE ( CONSENT_ID VARCHAR(255) NOT NULL, ATT_KEY VARCHAR(255) NOT NULL, - ATT_VALUE VARCHAR(255) NOT NULL, + ATT_VALUE VARCHAR(1023) NOT NULL, PRIMARY KEY(CONSENT_ID, ATT_KEY), CONSTRAINT FK_OB_CONSENT_ATTRIBUTE FOREIGN KEY (CONSENT_ID) REFERENCES OB_CONSENT (CONSENT_ID) ON DELETE CASCADE ) diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/oracle.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/oracle.sql index 267c39ff..743a5c49 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/oracle.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/oracle.sql @@ -77,7 +77,7 @@ CREATE TABLE OB_CONSENT_FILE ( CREATE TABLE OB_CONSENT_ATTRIBUTE ( CONSENT_ID VARCHAR(255) NOT NULL, ATT_KEY VARCHAR(255) NOT NULL, - ATT_VALUE VARCHAR(255) NOT NULL, + ATT_VALUE VARCHAR(1023) NOT NULL, PRIMARY KEY(CONSENT_ID, ATT_KEY), CONSTRAINT FK_OB_CONSENT_ATTRIBUTE FOREIGN KEY (CONSENT_ID) REFERENCES OB_CONSENT (CONSENT_ID) ON DELETE CASCADE ); diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/postgresql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/postgresql.sql index 1be43568..fa1147b4 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/postgresql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/consent/postgresql.sql @@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS OB_CONSENT_FILE ( CREATE TABLE IF NOT EXISTS OB_CONSENT_ATTRIBUTE ( CONSENT_ID VARCHAR(255) NOT NULL, ATT_KEY VARCHAR(255) NOT NULL, - ATT_VALUE VARCHAR(255) NOT NULL, + ATT_VALUE VARCHAR(1023) NOT NULL, PRIMARY KEY(CONSENT_ID, ATT_KEY), CONSTRAINT FK_OB_CONSENT_ATTRIBUTE FOREIGN KEY (CONSENT_ID) REFERENCES OB_CONSENT (CONSENT_ID) ON DELETE CASCADE ); diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mssql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mssql.sql index 6419446c..428f201f 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mssql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mssql.sql @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +-- All the data related to time are stored in unix time stamp and therefore, the data types for the time related data +-- are represented in BIGINT. +-- Since the database systems does not support adding default unix time to the database columns, the default data +-- storing is handled within the database querieS. + CREATE TABLE OB_NOTIFICATION ( NOTIFICATION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mysql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mysql.sql index fbbfa516..1da13b5c 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mysql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/mysql.sql @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +-- All the data related to time are stored in unix time stamp and therefore, the data types for the time related data +-- are represented in BIGINT. +-- Since the database systems does not support adding default unix time to the database columns, the default data +-- storing is handled within the database querieS. + -- For event notifications feature run the following queries against the openbank_openbankingdb-- CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/oracle.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/oracle.sql index 176c0d97..478fb598 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/oracle.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/oracle.sql @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +-- All the data related to time are stored in unix time stamp and therefore, the data types for the time related data +-- are represented in BIGINT. +-- Since the database systems does not support adding default unix time to the database columns, the default data +-- storing is handled within the database querieS. + CREATE TABLE OB_NOTIFICATION ( NOTIFICATION_ID varchar2(36) NOT NULL, CLIENT_ID varchar2(255) NOT NULL, @@ -26,7 +49,6 @@ BEGIN SELECT OB_NOTIFICATION_EVENT_seq.NEXTVAL INTO :NEW.EVENT_ID FROM DUAL; END; - CREATE TABLE OB_NOTIFICATION_ERROR ( NOTIFICATION_ID varchar2(36) NOT NULL, ERROR_CODE varchar2(255) NOT NULL, @@ -52,5 +74,3 @@ CREATE TABLE OB_NOTIFICATION_SUBSCRIBED_EVENTS ( PRIMARY KEY (SUBSCRIPTION_ID, EVENT_TYPE), CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES OB_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) ); - - diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/postgresql.sql b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/postgresql.sql index 971e6487..fb616f99 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/postgresql.sql +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/dbscripts/open-banking/event-notifications/postgresql.sql @@ -1,3 +1,26 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +-- All the data related to time are stored in unix time stamp and therefore, the data types for the time related data +-- are represented in BIGINT. +-- Since the database systems does not support adding default unix time to the database columns, the default data +-- storing is handled within the database querieS. + -- For event notifications feature run the following queries against the openbank_openbankingdb-- CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#application/META-INF/maven/com.wso2/openbanking-application-info-endpoint/pom.xml b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#application/META-INF/maven/com.wso2/openbanking-application-info-endpoint/pom.xml index 6af5d071..3fbb955c 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#application/META-INF/maven/com.wso2/openbanking-application-info-endpoint/pom.xml +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#application/META-INF/maven/com.wso2/openbanking-application-info-endpoint/pom.xml @@ -22,8 +22,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../../pom.xml 4.0.0 @@ -64,12 +64,12 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#consent/META-INF/maven/com.wso2/openbanking-consent-endpoint/pom.xml b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#consent/META-INF/maven/com.wso2/openbanking-consent-endpoint/pom.xml index 6a9e406d..80248e96 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#consent/META-INF/maven/com.wso2/openbanking-consent-endpoint/pom.xml +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#consent/META-INF/maven/com.wso2/openbanking-consent-endpoint/pom.xml @@ -24,8 +24,8 @@ open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../../pom.xml @@ -63,7 +63,7 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -74,7 +74,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao @@ -85,7 +85,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service @@ -107,7 +107,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#dynamic-client-registration/META-INF/maven/com.wso2/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#dynamic-client-registration/META-INF/maven/com.wso2/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml index ceabea67..576a7cea 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#dynamic-client-registration/META-INF/maven/com.wso2/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/api#openbanking#dynamic-client-registration/META-INF/maven/com.wso2/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml @@ -21,8 +21,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../../pom.xml 4.0.0 @@ -67,7 +67,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -78,7 +78,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/ob#authenticationendpoint/META-INF/maven/com.wso2/com.wso2.openbanking.authentication.webapp/pom.xml b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/ob#authenticationendpoint/META-INF/maven/com.wso2/com.wso2.openbanking.authentication.webapp/pom.xml index aec46e33..2218c8b3 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/ob#authenticationendpoint/META-INF/maven/com.wso2/com.wso2.openbanking.authentication.webapp/pom.xml +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/deployment/server/webapps/ob#authenticationendpoint/META-INF/maven/com.wso2/com.wso2.openbanking.authentication.webapp/pom.xml @@ -22,8 +22,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../../pom.xml 4.0.0 @@ -34,12 +34,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions provided diff --git a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 index 9b0a5cfa..942ebc8e 100644 --- a/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 +++ b/open-banking-accelerator/accelerators/ob-is/carbon-home/repository/resources/conf/templates/repository/conf/open-banking.xml.j2 @@ -93,6 +93,7 @@ {% endfor %} {% else %} com.wso2.openbanking.accelerator.identity.token.validators.MTLSEnforcementValidator + com.wso2.openbanking.accelerator.identity.token.validators.MTLSCertificateValidator com.wso2.openbanking.accelerator.identity.token.validators.SignatureAlgorithmEnforcementValidator com.wso2.openbanking.accelerator.identity.token.validators.ClientAuthenticatorValidator {% endif %} @@ -206,6 +207,11 @@ {% else %} https://localhost:8243/open-banking/{version}/cbpii/ {% endif %} + {% if open_banking.consent.vrp_consent_self_link is defined %} + {{open_banking.consent.vrp_consent_self_link}} + {% else %} + https://localhost:8243/open-banking/{version}/vrp/ + {% endif %} {% if open_banking.consent.data_retention.enabled is defined %} {{open_banking.consent.data_retention.enabled}} @@ -390,6 +396,19 @@ {% endif %} + + {% if open_banking.consent.idempotency.enabled is defined %} + {{open_banking.consent.idempotency.enabled}} + {% else %} + false + {% endif %} + + {% if open_banking.consent.idempotency.allowed_time_duration is defined %} + {{open_banking.consent.idempotency.allowed_time_duration}} + {% else %} + 1440 + {% endif %} + {% if open_banking.dcr.validator is defined %} @@ -455,6 +474,23 @@ https://localhost:8243/open-banking/0.1/register/ {% endif %} + + {% if open_banking.dcr.registration.software_environment_identification.ssa_property_name is defined %} + {{open_banking.dcr.registration.software_environment_identification.ssa_property_name}} + {% else %} + software_environment + {% endif %} + {% if open_banking.dcr.registration.software_environment_identification.ssa_property_value_for_sandbox is defined %} + {{open_banking.dcr.registration.software_environment_identification.ssa_property_value_for_sandbox}} + {% else %} + sandbox + {% endif %} + {% if open_banking.dcr.registration.software_environment_identification.ssa_property_value_for_production is defined %} + {{open_banking.dcr.registration.software_environment_identification.ssa_property_value_for_production}} + {% else %} + production + {% endif %} + {% if open_banking.dcr.registration.grant_types.required is defined %} {{open_banking.dcr.registration.grant_types.required}} @@ -769,6 +805,13 @@ {{open_banking.sca.idp.step}} {% endif %} + + {% if open_banking.analytics.elk is defined %} + {{open_banking.analytics.elk.enabled}} + {% else %} + false + {% endif %} + {% if open_banking.data_publishing.enable is defined %} {{open_banking.data_publishing.enable}} @@ -992,84 +1035,6 @@ {% endif %} - - - {% if open_banking.distributed_cache.enabled is defined %} - {{open_banking.distributed_cache.enabled}} - {% else %} - false - {% endif %} - {% if open_banking.distributed_cache.host_name is defined %} - {{open_banking.distributed_cache.host_name}} - {% else %} - localhost - {% endif %} - {% if open_banking.distributed_cache.port is defined %} - {{open_banking.distributed_cache.port}} - {% else %} - 5701 - {% endif %} - {% if ( (open_banking.distributed_cache.discovery_mechanism is defined) and (open_banking.distributed_cache.discovery_mechanism == "TCP") ) %} - {{open_banking.distributed_cache.discovery_mechanism}} - {% if open_banking.distributed_cache.members is defined %} - - {% for member in open_banking.distributed_cache.members %} - {{member}} - {% endfor %} - - {% else %} - - {% endif %} - {% else %} - Multicast - {% if open_banking.distributed_cache.multicast_group is defined %} - {{open_banking.distributed_cache.multicast_group}} - {% else %} - 224.2.2.3 - {% endif %} - {% if open_banking.distributed_cache.multicast_port is defined %} - {{open_banking.distributed_cache.multicast_port}} - {% else %} - 54321 - {% endif %} - {% if open_banking.distributed_cache.trusted_interfaces is defined %} - - {% for trusted_interface in open_banking.distributed_cache.trusted_interfaces %} - {{trusted_interface}} - {% endfor %} - - {% else %} - - {% endif %} - {% endif %} - - {% if open_banking.distributed_cache.properties.max_heartbeat is defined %} - {{open_banking.distributed_cache.properties.max_heartbeat}} - {% else %} - 600 - {% endif %} - {% if open_banking.distributed_cache.properties.max_master_confirmation is defined %} - {{open_banking.distributed_cache.properties.max_master_confirmation}} - {% else %} - 900 - {% endif %} - {% if open_banking.distributed_cache.properties.merge_first_run_delay is defined %} - {{open_banking.distributed_cache.properties.merge_first_run_delay}} - {% else %} - 60 - {% endif %} - {% if open_banking.distributed_cache.properties.merge_next_run_delay is defined %} - {{open_banking.distributed_cache.properties.merge_next_run_delay}} - {% else %} - 30 - {% endif %} - {% if open_banking.distributed_cache.properties.logging_type is defined %} - {{open_banking.distributed_cache.properties.logging_type}} - {% else %} - none - {% endif %} - - {% for worker in open_banking.identity.authentication.worker %} 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml @@ -46,7 +46,6 @@ ${project.basedir}/carbon-home/repository/components/lib **/commons-beanutils-1.9.4.jar - **/mysql-connector-java-5.1.44.jar **/hibernate-validator-6.0.20.Final.jar **/validation-api-2.0.1.Final.jar @@ -60,7 +59,6 @@ **/org.wso2.carbon.identity.application.authenticator.push-0.1.1.jar **/org.wso2.carbon.identity.application.authenticator.push.common-0.1.1.jar **/org.wso2.carbon.identity.application.authenticator.push.device.handler-0.1.1.jar - **/hazelcast-5.0.2.jar diff --git a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-5.11.0-deployment.toml b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-5.11.0-deployment.toml index 9b7bdf22..2058ab3d 100644 --- a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-5.11.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-5.11.0-deployment.toml @@ -406,6 +406,12 @@ read_timeout = 3000 [[open_banking.dcr.regulatory_issuers.iss]] name = "OpenBanking Ltd" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #Signature algorithm types that are allowed #[[open_banking.signature_validation.allowed_algorithms]] #name = "PS256" @@ -430,6 +436,9 @@ name = "OpenBanking Ltd" #required = false #allowed_values = ["web"] +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.0.0-deployment.toml b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.0.0-deployment.toml index 0798f3d3..2160f0ac 100644 --- a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.0.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.0.0-deployment.toml @@ -406,6 +406,12 @@ read_timeout = 3000 [[open_banking.dcr.regulatory_issuers.iss]] name = "OpenBanking Ltd" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #Signature algorithm types that are allowed #[[open_banking.signature_validation.allowed_algorithms]] #name = "PS256" @@ -430,6 +436,9 @@ name = "OpenBanking Ltd" #required = false #allowed_values = ["web"] +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.1.0-deployment.toml b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.1.0-deployment.toml index 0b6e3cbb..1c5792ec 100644 --- a/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.1.0-deployment.toml +++ b/open-banking-accelerator/accelerators/ob-is/repository/resources/wso2is-6.1.0-deployment.toml @@ -406,6 +406,12 @@ read_timeout = 3000 [[open_banking.dcr.regulatory_issuers.iss]] name = "OpenBanking Ltd" +[open_banking.dcr.registration.software_environment_identification] +ssa_property_name = "software_environment" +# If both below values doesnt match, Then software_environment is default to production. +ssa_property_value_for_sandbox = "sandbox" +ssa_property_value_for_production = "production" + #Signature algorithm types that are allowed #[[open_banking.signature_validation.allowed_algorithms]] #name = "PS256" @@ -430,6 +436,9 @@ name = "OpenBanking Ltd" #required = false #allowed_values = ["web"] +[open_banking.analytics.elk] +enabled = false + [open_banking.data_publishing] enable = false username="$ref{super_admin.username}@carbon.super" diff --git a/open-banking-accelerator/accelerators/pom.xml b/open-banking-accelerator/accelerators/pom.xml index 286193d6..4064fe5d 100644 --- a/open-banking-accelerator/accelerators/pom.xml +++ b/open-banking-accelerator/accelerators/pom.xml @@ -21,9 +21,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../../pom.xml diff --git a/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/pom.xml b/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/pom.xml index d687f956..8003b149 100644 --- a/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/pom.xml +++ b/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/pom.xml @@ -18,8 +18,8 @@ open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -72,7 +72,7 @@ powermock-api-mockito - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common diff --git a/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/src/main/java/com/wso2/openbanking/accelerator/account/metadata/service/service/AccountMetadataService.java b/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/src/main/java/com/wso2/openbanking/accelerator/account/metadata/service/service/AccountMetadataService.java index eb94c088..2350e26b 100644 --- a/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/src/main/java/com/wso2/openbanking/accelerator/account/metadata/service/service/AccountMetadataService.java +++ b/open-banking-accelerator/components/account-metadata/com.wso2.openbanking.accelerator.account.metadata.service/src/main/java/com/wso2/openbanking/accelerator/account/metadata/service/service/AccountMetadataService.java @@ -23,9 +23,9 @@ import java.util.Map; /** - * Account Metadata Service + * Account Metadata Service. *

- * Handles the calls for persisting and retrieving metadata related to accounts + * Handles the calls for persisting and retrieving metadata related to accounts. */ public interface AccountMetadataService { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.ciba/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.ciba/pom.xml index ebefa72d..3e35d80f 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.ciba/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.ciba/pom.xml @@ -24,8 +24,8 @@ open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../pom.xml com.wso2.openbanking.accelerator.ciba @@ -33,12 +33,12 @@ WSO2 Open Banking - Common component - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided @@ -61,7 +61,7 @@ powermock-api-mockito - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/pom.xml index 367041df..870e3fdd 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml @@ -34,8 +32,12 @@ WSO2 Open Banking - Common component - com.hazelcast - hazelcast + org.wso2.orbit.org.bouncycastle + bcpkix-jdk18on + + + org.wso2.orbit.org.bouncycastle + bcprov-jdk18on org.apache.ws.commons.axiom.wso2 @@ -52,10 +54,22 @@ org.wso2.carbon.identity.inbound.auth.oauth2 org.wso2.carbon.identity.oauth + + + org.wso2.orbit.org.bouncycastle + bcprov-jdk15on + + org.wso2.carbon.identity.framework org.wso2.carbon.identity.application.mgt + + + org.wso2.orbit.org.bouncycastle + bcprov-jdk15on + + org.hibernate @@ -82,6 +96,10 @@ org.wso2.orbit.com.hazelcast hazelcast + + org.wso2.orbit.org.bouncycastle + bcprov-jdk15on + @@ -106,10 +124,6 @@ io.jsonwebtoken jjwt - - org.bouncycastle - bcpkix-jdk15on - org.wso2.orbit.com.nimbusds nimbus-jose-jwt @@ -183,6 +197,7 @@ **/JDBCPersistenceManager.class **/CertValidationErrors.class **/JDBCRetentionDataPersistenceManager.class + **/*Type*/** @@ -275,10 +290,7 @@ org.osgi.framework;version="${osgi.framework.imp.pkg.version.range}", - org.osgi.service.component;version="${osgi.service.component.imp.pkg.version.range}", - com.hazelcast.config; version="${com.hazelcast.hazelcast.version}", - com.hazelcast.core; version="${com.hazelcast.hazelcast.version}", - com.hazelcast.map; version="${com.hazelcast.hazelcast.version}" + org.osgi.service.component;version="${osgi.service.component.imp.pkg.version.range}" !com.wso2.openbanking.accelerator.common.internal, diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/caching/OpenBankingBaseCache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/caching/OpenBankingBaseCache.java index 37c485a2..1c41b245 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/caching/OpenBankingBaseCache.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/caching/OpenBankingBaseCache.java @@ -33,8 +33,8 @@ /** * Abstract cache manager for Open Banking. * - * @param - * @param + * @param Extended Cache Key + * @param Cache Value */ public abstract class OpenBankingBaseCache { @@ -54,7 +54,7 @@ public interface OnDemandRetriever { /** * Initialize With unique cache name. * - * @param cacheName + * @param cacheName unique cache name. */ public OpenBankingBaseCache(String cacheName) { @@ -68,10 +68,10 @@ public OpenBankingBaseCache(String cacheName) { /** * Get from cache or invoke ondemand retriever and store. * - * @param key - * @param onDemandRetriever - * @return - * @throws OpenBankingException + * @param key cache key. + * @param onDemandRetriever on demand retriever. + * @return cached object. + * @throws OpenBankingException if an error occurs while retrieving the object */ public V getFromCacheOrRetrieve(K key, OnDemandRetriever onDemandRetriever) throws OpenBankingException { @@ -132,8 +132,8 @@ public V getFromCache(K key) { /** * Add Object to cache. * - * @param key - * @param value + * @param key cache key. + * @param value cache value. */ public void addToCache(K key, V value) { @@ -149,7 +149,7 @@ public void addToCache(K key, V value) { /** * Remove Object from Cache. * - * @param key + * @param key cache key. */ public void removeFromCache(K key) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/config/OpenBankingConfigParser.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/config/OpenBankingConfigParser.java index e43625cd..32486797 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/config/OpenBankingConfigParser.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/config/OpenBankingConfigParser.java @@ -38,6 +38,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; @@ -112,7 +113,7 @@ public static OpenBankingConfigParser getInstance() { * * @param filePath Custom file path * @return OpenBankingConfigParser object - * @Deprecated use OpenBankingConfigParser.getInstance() + * @Deprecated use OpenBankingConfigParser.getInstance() */ @Deprecated public static OpenBankingConfigParser getInstance(String filePath) { @@ -563,29 +564,32 @@ private void buildAllowedSubscriptions() { new QName(OpenBankingConstants.OB_CONFIG_QNAME, OpenBankingConstants.DCR_CONFIG_TAG)); if (dcrElement != null) { - OMElement regulatoryAPINames = dcrElement.getFirstChildWithName( - new QName(OpenBankingConstants.OB_CONFIG_QNAME, OpenBankingConstants.REGULATORY_APINAMES)); + OMElement regulatoryAPIs = dcrElement.getFirstChildWithName( + new QName(OpenBankingConstants.OB_CONFIG_QNAME, OpenBankingConstants.REGULATORY_API_NAMES)); - if (regulatoryAPINames != null) { + if (regulatoryAPIs != null) { - //obtaining each scope under allowed scopes + //obtaining each regulatory API under allowed regulatory APIs Iterator environmentIterator = - regulatoryAPINames.getChildrenWithLocalName(OpenBankingConstants.REGULATORY_API); + regulatoryAPIs.getChildrenWithLocalName(OpenBankingConstants.REGULATORY_API); while (environmentIterator.hasNext()) { - OMElement scopeElem = (OMElement) environmentIterator.next(); - String scopeName = scopeElem.getAttributeValue(new QName("name")); - String rolesStr = scopeElem.getAttributeValue(new QName("roles")); + OMElement regulatoryAPIElem = (OMElement) environmentIterator.next(); + String regulatoryAPIName = regulatoryAPIElem.getAttributeValue(new QName( + OpenBankingConstants.API_NAME)); + String rolesStr = regulatoryAPIElem.getAttributeValue(new QName( + OpenBankingConstants.API_ROLE)); if (StringUtils.isNotEmpty(rolesStr)) { List rolesList = Arrays.stream(rolesStr.split(",")) .map(String::trim) .collect(Collectors.toList()); - allowedAPIs.put(scopeName, rolesList); + allowedAPIs.put(regulatoryAPIName, rolesList); + } else { + allowedAPIs.put(regulatoryAPIName, Collections.emptyList()); } } } } - } private void buildOBEventExecutors() { @@ -785,7 +789,7 @@ public int getConnectionVerificationTimeout() { /** * Returns the retention datasource name configured in open-banking.xml. - * @return + * @return retention datasource name or empty string if nothing is configured */ public String getRetentionDataSourceName() { @@ -1142,7 +1146,7 @@ public String getOBIdnRetrieverSandboxCertificateKid() { /** * JWKS Retriever Size Limit for JWS Signature Handling. * - * @return + * @return JWKS Retriever Size Limit */ public String getJwksRetrieverSizeLimit() { @@ -1153,7 +1157,7 @@ public String getJwksRetrieverSizeLimit() { /** * JWKS Retriever Connection Timeout for JWS Signature Handling. * - * @return + * @return JWKS Retriever Connection Timeout */ public String getJwksRetrieverConnectionTimeout() { @@ -1164,7 +1168,7 @@ public String getJwksRetrieverConnectionTimeout() { /** * JWKS Retriever Read Timeout for JWS Signature Handling. * - * @return + * @return JWKS Retriever Read Timeout */ public String getJwksRetrieverReadTimeout() { @@ -1199,7 +1203,7 @@ public boolean isJwsResponseSigningEnabled() { /** * Jws Request Signing allowed algorithms. * - * @return + * @return Jws Request Signing allowed algorithms */ public List getJwsRequestSigningAlgorithms() { @@ -1218,7 +1222,7 @@ public List getJwsRequestSigningAlgorithms() { /** * Jws Response Signing allowed algorithm. * - * @return + * @return Jws Response Signing allowed algorithm */ public String getJwsResponseSigningAlgorithm() { @@ -1397,6 +1401,40 @@ public String getRealtimeEventNotificationRequestGenerator() { : (String) getConfigElementFromKey(OpenBankingConstants.REALTIME_EVENT_NOTIFICATION_REQUEST_GENERATOR); } + /** + * Method to get software environment identification SSA property name. + * + * @return String software environment identification SSA property name. + */ + public String getSoftwareEnvIdentificationSSAPropertyName() { + return getConfigElementFromKey(OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_PROPERTY_NAME) == null ? + OpenBankingConstants.SOFTWARE_ENVIRONMENT : (String) getConfigElementFromKey( + OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_PROPERTY_NAME); + } + + /** + * Method to get software environment identification value for sandbox in SSA. + * + * @return String software environment identification value for sandbox. + */ + public String getSoftwareEnvIdentificationSSAPropertyValueForSandbox() { + return getConfigElementFromKey(OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_SANDBOX) == null ? + "sandbox" : (String) getConfigElementFromKey( + OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_SANDBOX); + } + + /** + * Method to get software environment identification value for production in SSA. + * + * @return String software environment identification value for production. + */ + public String getSoftwareEnvIdentificationSSAPropertyValueForProduction() { + return getConfigElementFromKey( + OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_PRODUCTION) == null ? + "production" : (String) getConfigElementFromKey( + OpenBankingConstants.DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_PRODUCTION); + } + /** * Get config related for checking whether PSU is a federated user or not. * @@ -1423,4 +1461,23 @@ public String getFederatedIDPName() { ((String) getConfigElementFromKey(OpenBankingConstants.PSU_FEDERATED_IDP_NAME)).trim(); } + /** + * Method to get the value Idempotency enable configuration. + * @return Whether Idempotency is enabled or not + */ + public boolean isIdempotencyValidationEnabled() { + return getConfigElementFromKey(OpenBankingConstants.IDEMPOTENCY_IS_ENABLED) != null && + Boolean.parseBoolean(((String) + getConfigElementFromKey(OpenBankingConstants.IDEMPOTENCY_IS_ENABLED)).trim()); + } + + /** + * Method to get the value Idempotency allowed time configuration. + * @return Idempotency allowed time + */ + public String getIdempotencyAllowedTime() { + return getConfigElementFromKey(OpenBankingConstants.IDEMPOTENCY_ALLOWED_TIME) == null ? "1440" : + (String) getConfigElementFromKey(OpenBankingConstants.IDEMPOTENCY_ALLOWED_TIME); + } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/constant/OpenBankingConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/constant/OpenBankingConstants.java index 52409911..f04b3229 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/constant/OpenBankingConstants.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/constant/OpenBankingConstants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -62,16 +62,28 @@ public class OpenBankingConstants { public static final String DCR_JWKS_NAME = "DCR.JWKSEndpointName"; public static final String DCR_APPLICATION_NAME_KEY = "DCR.ApplicationName"; public static final String OB_KM_NAME = "KeyManagerName"; + public static final String DCR_SOFTWARE_ENV_IDENTIFICATION_PROPERTY_NAME = + "DCR.RegistrationRequestParams.SoftwareEnvironmentIdentification.PropertyName"; + public static final String DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_SANDBOX = + "DCR.RegistrationRequestParams.SoftwareEnvironmentIdentification.PropertyValueForSandbox"; + public static final String DCR_SOFTWARE_ENV_IDENTIFICATION_VALUE_FOR_PRODUCTION = + "DCR.RegistrationRequestParams.SoftwareEnvironmentIdentification.PropertyValueForProduction"; public static final String APIM_APPCREATION = "DCR.APIMRESTEndPoints.AppCreation"; public static final String APIM_KEYGENERATION = "DCR.APIMRESTEndPoints.KeyGeneration"; public static final String APIM_GETAPIS = "DCR.APIMRESTEndPoints.RetrieveAPIS"; public static final String APIM_SUBSCRIBEAPIS = "DCR.APIMRESTEndPoints.SubscribeAPIs"; public static final String APIM_GETSUBSCRIPTIONS = "DCR.APIMRESTEndPoints.RetrieveSubscribedAPIs"; - public static final String REGULATORY_APINAMES = "RegulatoryAPINames"; + public static final String REGULATORY_API_NAMES = "RegulatoryAPINames"; + public static final String API_NAME = "name"; + public static final String API_ROLE = "roles"; + public static final String API_ID = "id"; + public static final String API_LIST = "list"; public static final String REGULATORY_API = "API"; public static final String SOFTWARE_ROLES = "software_roles"; public static final String SOFTWARE_STATEMENT = "software_statement"; + public static final String SOFTWARE_ID = "software_id"; + public static final String JWT_BODY = "body"; public static final String SOFTWARE_ENVIRONMENT = "software_environment"; public static final String TOKEN_ENDPOINT = "DCR.TokenEndpoint"; public static final String STORE_HOSTNAME = "PublisherURL"; @@ -125,6 +137,10 @@ public class OpenBankingConstants { ".CertificateManagement.TPPValidationService.ScopeRegexPatterns.PISP"; public static final String TPP_VALIDATION_SERVICE_CBPII_SCOPE_REGEX = "Gateway" + ".CertificateManagement.TPPValidationService.ScopeRegexPatterns.CBPII"; + public static final String CLIENT_TRANSPORT_CERT_HEADER_NAME = "Gateway" + + ".CertificateManagement.ClientTransportCertHeaderName"; + public static final String URL_ENCODE_CLIENT_TRANSPORT_CERT_HEADER_ENABLED = "Gateway" + + ".CertificateManagement.UrlEncodeClientTransportCertHeaderEnabled"; public static final int PAGINATION_LIMIT_DEFAULT = 25; public static final int PAGINATION_OFFSET_DEFAULT = 0; public static final String CONSENT_CONFIG_TAG = "Consent"; @@ -249,4 +265,8 @@ public class OpenBankingConstants { public static final String QUERY = "query"; public static final String IS_PSU_FEDERATED = "PSUFederatedAuthentication.Enabled"; public static final String PSU_FEDERATED_IDP_NAME = "PSUFederatedAuthentication.IDPName"; + public static final String IDEMPOTENCY_IS_ENABLED = "Consent.Idempotency.Enabled"; + public static final String IDEMPOTENCY_ALLOWED_TIME = "Consent.Idempotency.AllowedTimeDuration"; + public static final String DOT_SEPARATOR = "."; } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCache.java deleted file mode 100644 index 145d9cd4..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCache.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.distributed.caching; - -import com.hazelcast.map.IMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.concurrent.TimeUnit; - -/** - * Abstract cache manager for Open Banking Distributed cache. - * - * @param Key of the cache. - * @param Value of the cache. - */ -public abstract class OpenBankingDistributedCache { - private final String cacheName; - - private static final Log log = LogFactory.getLog(OpenBankingDistributedCache.class); - - /** - * Initialize With unique cache name. - * - * @param cacheName Name of the cache. - */ - public OpenBankingDistributedCache(String cacheName) { - - this.cacheName = cacheName; - if (log.isDebugEnabled()) { - log.debug(String.format("Distributed Cache initialized for %s.", cacheName.replaceAll("[\r\n]", ""))); - } - } - - /** - * Get from cache. - * - * @param key cache key. - * @return cache. - */ - public V getFromCache(K key) { - - if (isEnabled()) { - - IMap cache = getBaseCache(); - - if (cache.containsKey(key)) { - if (log.isDebugEnabled()) { - log.debug(String.format("Found cache entry `%s` in cache %s.", - key.toString().replaceAll("[\r\n]", ""), cacheName.replaceAll("[\r\n]", ""))); - } - return cache.get(key); - } else { - if (log.isDebugEnabled()) { - log.debug(String.format("Cache entry `%s` is not Found in cache %s.", - key.toString().replaceAll("[\r\n]", ""), cacheName.replaceAll("[\r\n]", ""))); - } - return null; - } - } else { - log.debug("Distributed cache is Disabled."); - return null; - } - } - - /** - * Add Object to cache. - * - * @param key cache key. - * @param value object to be cached. - */ - public void addToCache(K key, V value) { - if (isEnabled()) { - IMap cache = getBaseCache(); - if (log.isDebugEnabled()) { - log.debug(String.format("`%s` added into cache %s.", key.toString().replaceAll("[\r\n]", ""), - cacheName.replaceAll("[\r\n]", ""))); - } - cache.put(key, value, getCacheTimeToLiveMinutes(), TimeUnit.MINUTES); - } else { - log.debug("Distributed cache is Disabled."); - } - } - - /** - * Remove from cache. - * - * @param key cache key. - */ - public void removeFromCache(K key) { - if (isEnabled()) { - if (log.isDebugEnabled()) { - log.debug(String.format("`%s` removed from cache %s.", key.toString().replaceAll("[\r\n]", ""), - cacheName.replaceAll("[\r\n]", ""))); - } - IMap cache = getBaseCache(); - cache.remove(key); - } else { - log.debug("Distributed cache is Disabled."); - } - } - - /** - * Method to check if the cache is empty. - * - * @return true if empty, false if populated. - */ - public boolean isEmpty() { - return getBaseCache().isEmpty(); - } - - /** - * Get the clustered cache. - * - * @return cache map. - */ - private IMap getBaseCache() { - return OpenBankingDistributedMember.of().getHazelcastInstance().getMap(this.cacheName); - } - - /** - * Method to get if the Distributed caching is enabled. - * - * @return True if enabled, false if disabled. - */ - private boolean isEnabled() { - return OpenBankingDistributedMember.of().isEnabled(); - } - - /** - * Get Cache expiry time upon modification in minutes. - * - * @return integer denoting number of minutes. - */ - public abstract int getCacheTimeToLiveMinutes(); - -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheConstants.java deleted file mode 100644 index 58d5bf75..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheConstants.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.distributed.caching; - -/** - * Open banking distributed cache constants. - */ -public class OpenBankingDistributedCacheConstants { - - // Distributed cache cluster name. - public static final String CLUSTER_NAME = "OB_DISTRIBUTED_CACHE"; - - // Common constants for both TCP and Multicast. - public static final String ENABLED = "DistributedCache.Enabled"; - public static final String HOST_NAME = "DistributedCache.HostName"; - public static final String PORT = "DistributedCache.Port"; - public static final String DISCOVERY_MECHANISM = "DistributedCache.DiscoveryMechanism"; - - // Constants used for Multicast. - public static final String MULTICAST = "Multicast"; - public static final String MULTICAST_GROUP = "DistributedCache.MulticastGroup"; - public static final String MULTICAST_PORT = "DistributedCache.MulticastPort"; - public static final String TRUSTED_INTERFACES = "DistributedCache.TrustedInterfaces.TrustedInterface"; - - // Constants used for TCP. - public static final String TCP = "TCP"; - public static final String MEMBERS = "DistributedCache.Members.Member"; - - // Constants for hazelcast properties. - public static final String PROPERTY_MAX_HEARTBEAT = "DistributedCache.Properties.MaxHeartbeat"; - public static final String PROPERTY_MAX_MASTER_CONFIRMATION = "DistributedCache.Properties.MasterConfirmation"; - public static final String PROPERTY_MERGE_FIRST_RUN_DELAY = "DistributedCache.Properties.MergeFirstRunDelay"; - public static final String PROPERTY_MERGE_NEXT_RUN_DELAY = "DistributedCache.Properties.MergeNextRunDelay"; - public static final String PROPERTY_LOGGING_TYPE = "DistributedCache.Properties.LoggingType"; - - // Hazelcast Constants for hazelcast properties. - public static final String HAZELCAST_PROPERTY_MAX_HEARTBEAT = "hazelcast.max.no.heartbeat.seconds"; - public static final String HAZELCAST_PROPERTY_MAX_MASTER_CONFIRMATION = "hazelcast.max.no.master." + - "confirmation.seconds"; - public static final String HAZELCAST_PROPERTY_MERGE_FIRST_RUN_DELAY = "hazelcast.merge.first.run.delay.seconds"; - public static final String HAZELCAST_PROPERTY_MERGE_NEXT_RUN_DELAY = "hazelcast.merge.next.run.delay.seconds"; - public static final String HAZELCAST_PROPERTY_LOGGING_TYPE = "hazelcast.logging.type"; -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheKey.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheKey.java deleted file mode 100644 index b1818a73..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedCacheKey.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.distributed.caching; - -import java.io.Serializable; -import java.util.Objects; - -/** - * Abstract class for Open Banking Distributed Cache Key. - */ -public class OpenBankingDistributedCacheKey implements Serializable { - - private static final long serialVersionUID = -2106706990466051087L; - private String cacheKey; - - - /** - * public constructor for OpenBankingDistributedCacheKey. - * - * @param cacheKey String cache key. - */ - public OpenBankingDistributedCacheKey(String cacheKey) { - setCacheKey(cacheKey); - } - - /** - * Get Instance OpenBankingDistributedCacheKey. - * - * @param cacheKey String cache key. - * @return new OpenBankingDistributedCacheKey instance. - */ - public static OpenBankingDistributedCacheKey of(String cacheKey) { - return new OpenBankingDistributedCacheKey(cacheKey); - } - - /** - * Getter for cacheKey. - * - * @return String cacheKey. - */ - public String getCacheKey() { - return this.cacheKey; - } - - /** - * Setter for cacheKey. - * - * @param cacheKey String cacheKey. - */ - public void setCacheKey(String cacheKey) { - this.cacheKey = cacheKey; - } - - /** - * Equals Method for OpenBankingDistributedCacheKey objects. - * - * @param o Object. - * @return True if equal, false if not-equal. - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - OpenBankingDistributedCacheKey that = (OpenBankingDistributedCacheKey) o; - return Objects.equals(getCacheKey(), that.getCacheKey()); - } - - /** - * hashcode for OpenBankingDistributedCacheKey. - * - * @return hashcode. - */ - @Override - public int hashCode() { - return Objects.hash(getCacheKey()); - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedMember.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedMember.java deleted file mode 100644 index 4c4147cf..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/distributed/caching/OpenBankingDistributedMember.java +++ /dev/null @@ -1,330 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.distributed.caching; - -import com.hazelcast.config.Config; -import com.hazelcast.config.JoinConfig; -import com.hazelcast.config.MulticastConfig; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.config.TcpIpConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.util.SecurityUtils; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; -import java.util.Map; -import java.util.Properties; - -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.CLUSTER_NAME; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.DISCOVERY_MECHANISM; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.ENABLED; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_LOGGING_TYPE; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MAX_HEARTBEAT; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MAX_MASTER_CONFIRMATION; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MERGE_FIRST_RUN_DELAY; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MERGE_NEXT_RUN_DELAY; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.HOST_NAME; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.MEMBERS; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.MULTICAST; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.MULTICAST_GROUP; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.MULTICAST_PORT; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PORT; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PROPERTY_LOGGING_TYPE; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PROPERTY_MAX_HEARTBEAT; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PROPERTY_MAX_MASTER_CONFIRMATION; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PROPERTY_MERGE_FIRST_RUN_DELAY; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.PROPERTY_MERGE_NEXT_RUN_DELAY; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.TCP; -import static com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants.TRUSTED_INTERFACES; - -/** - * Singleton class to create a hazelcast cluster member. - */ -public class OpenBankingDistributedMember { - private boolean enabled; - private static volatile OpenBankingDistributedMember openBankingDistributedMember; - private final HazelcastInstance hazelcastInstance; - private static final Map configurations = OpenBankingConfigParser.getInstance().getConfiguration(); - - private static final Log log = LogFactory.getLog(OpenBankingDistributedMember.class); - - /** - * Private constructor. - */ - private OpenBankingDistributedMember() { - setEnabled(); - - Config hazelcastConfig = new Config(); - hazelcastConfig.setClusterName(CLUSTER_NAME); - - setProperties(hazelcastConfig); - - NetworkConfig network = hazelcastConfig.getNetworkConfig(); - - setNetworkConfigurations(network); - - this.hazelcastInstance = Hazelcast.newHazelcastInstance(hazelcastConfig); - } - - /** - * Method to get the singleton object. - * - * @return distributedMember. - */ - public static OpenBankingDistributedMember of() { - if (openBankingDistributedMember == null) { - synchronized (OpenBankingDistributedMember.class) { - if (openBankingDistributedMember == null) { - openBankingDistributedMember = new OpenBankingDistributedMember(); - } - } - } - return openBankingDistributedMember; - } - - /** - * Method to destroy the singleton instance. - */ - public static synchronized void shutdown() { - openBankingDistributedMember.getHazelcastInstance().shutdown(); - openBankingDistributedMember = null; - log.debug("Shutdown distributed cache member."); - } - - /** - * Getter for enabled. - * - * @return Boolean enabled. - */ - public boolean isEnabled() { - return this.enabled; - } - - /** - * Setter for enabled, using the config file. - */ - public void setEnabled() { - Object isEnableConfiguration = configurations.get(ENABLED); - if (isEnableConfiguration != null) { - String isEnableConfigurationString = isEnableConfiguration.toString(); - setEnabled(isEnableConfigurationString.equals("true")); - } - } - - /** - * Setter of enabled. - * - * @param enabled Boolean enabled. - */ - public void setEnabled(boolean enabled) { - if (enabled) { - log.debug("Distributed Caching enabled"); - } else { - log.debug("Distributed Caching disabled"); - } - this.enabled = enabled; - } - - /** - * Getter for hazelcast instance. - * - * @return this.hazelcastInstance. - */ - public HazelcastInstance getHazelcastInstance() { - return this.hazelcastInstance; - } - - /** - * Method to set hazelcast properties. - * - * @param hazelcastConfig hazelcastConfig. - */ - @SuppressFBWarnings("CRLF_INJECTION_LOGS") - // Suppressed content - hazelcastConfig.getProperties() - // Suppression reason - Warning are appearing on Properties, not strings. Also the properties will be set in config - // by the admin - // Suppressed warning count - 1 - private synchronized void setProperties(Config hazelcastConfig) { - - Properties hazelcastProperties = new Properties(); - - setProperty(hazelcastProperties, PROPERTY_MAX_HEARTBEAT, HAZELCAST_PROPERTY_MAX_HEARTBEAT); - setProperty(hazelcastProperties, PROPERTY_MAX_MASTER_CONFIRMATION, HAZELCAST_PROPERTY_MAX_MASTER_CONFIRMATION); - setProperty(hazelcastProperties, PROPERTY_MERGE_FIRST_RUN_DELAY, HAZELCAST_PROPERTY_MERGE_FIRST_RUN_DELAY); - setProperty(hazelcastProperties, PROPERTY_MERGE_NEXT_RUN_DELAY, HAZELCAST_PROPERTY_MERGE_NEXT_RUN_DELAY); - setProperty(hazelcastProperties, PROPERTY_LOGGING_TYPE, HAZELCAST_PROPERTY_LOGGING_TYPE); - - hazelcastConfig.setProperties(hazelcastProperties); - - if (log.isDebugEnabled()) { - log.debug("Hazelcast Properties : " + hazelcastConfig.getProperties()); - } - } - - /** - * Method to set hazelcast property. - * - * @param property Property. - * @param configurationName Name of the configuration in config file. - * @param hazelcastProperty hazelcast configuration. - */ - private void setProperty(Properties property, String configurationName, String hazelcastProperty) { - Object configuration = configurations.get(configurationName); - if (configuration != null) { - String configurationString = configuration.toString(); - property.setProperty(hazelcastProperty, configurationString); - } - } - - /** - * Method to set hazelcast network configurations. - * - * @param network network. - */ - private synchronized void setNetworkConfigurations(NetworkConfig network) { - - // Configuring host name of the hazelcast instance. - Object hostName = configurations.get(HOST_NAME); - if (hostName != null) { - String hostNameString = hostName.toString(); - network.setPublicAddress(hostNameString); - } - - // Configuring port of the hazelcast instance. - Object port = configurations.get(PORT); - if (port != null) { - String portString = port.toString(); - int portInt = Integer.parseInt(portString); - network.setPort(portInt); - } - - if (log.isDebugEnabled()) { - log.debug("Network is set to " + network.getPublicAddress().replaceAll("[\r\n]", "") + ":" + - network.getPort()); - } - - // Configuring the discovery mechanism of the hazelcast instance. - JoinConfig join = network.getJoin(); - Object discoveryMechanism = configurations.get(DISCOVERY_MECHANISM); - if (discoveryMechanism != null) { // When discovery method is configured. - - String discoveryMechanismString = discoveryMechanism.toString(); - - if (discoveryMechanismString.equals(TCP)) { - // Discovery method TCP. - setConfigurationsTCP(join); - } else if (discoveryMechanismString.equals(MULTICAST)) { - // Discovery method Multicast. - setConfigurationsMulticast(join); - } - } else { // Defaulting Multicast when discovery method is not configured. - setConfigurationsMulticast(join); - } - } - - /** - * Method to set discovery mechanism TCP. - * - * @param join JoinConfig join. - */ - @SuppressFBWarnings("CRLF_INJECTION_LOGS") - // Suppressed content - tcpipConfig.getMembers() - // Suppression reason - False positive: New lines are already removed - // Suppressed warning count - 1 - private void setConfigurationsTCP(JoinConfig join) { - log.debug("Discovery mechanism : TCP"); - join.getMulticastConfig().setEnabled(false); - TcpIpConfig tcpipConfig = join.getTcpIpConfig(); - tcpipConfig.setEnabled(true); - - // Configuring TCP members. - Object members = configurations.get(MEMBERS); - if (members != null) { - ArrayList membersList = new ArrayList<>(); - if (members instanceof ArrayList) { - membersList.addAll((ArrayList) members); - } else if (members instanceof String) { - membersList.add((String) members); - } - for (String member : membersList) { - tcpipConfig.addMember(member.trim()); - } - } - if (log.isDebugEnabled()) { - log.debug("Members: " + SecurityUtils.sanitize(tcpipConfig.getMembers())); - } - } - - /** - * Method to set discovery mechanism Multicast. - * - * @param join JoinConfig join. - */ - @SuppressFBWarnings("CRLF_INJECTION_LOGS") - // Suppressed content - multicastConfig.getTrustedInterfaces() - // Suppression reason - False positive: New lines are already removed - // Suppressed warning count - 1 - private void setConfigurationsMulticast(JoinConfig join) { - log.debug("Discovery mechanism : Multicast"); - join.getTcpIpConfig().setEnabled(false); - MulticastConfig multicastConfig = join.getMulticastConfig(); - multicastConfig.setEnabled(true); - - // Configuring multicast group. - Object multicastGroup = configurations.get(MULTICAST_GROUP); - if (multicastGroup != null) { - String multicastGroupString = multicastGroup.toString(); - multicastConfig.setMulticastGroup(multicastGroupString); - } - - // Configuring multicast port. - Object multicastPort = configurations.get(MULTICAST_PORT); - if (multicastPort != null) { - String multicastPortString = multicastPort.toString(); - int multicastPortInt = Integer.parseInt(multicastPortString); - multicastConfig.setMulticastPort(multicastPortInt); - } - - if (log.isDebugEnabled()) { - log.debug("Discovery mechanism is set to Multicast.\n\tMulticast Group: " + - multicastConfig.getMulticastGroup().replaceAll("[\r\n]", "") + - "\n\tMulticast Port: " + multicastConfig.getMulticastPort()); - } - // Configuring trusted interfaces. - Object trustedInterfaces = configurations.get(TRUSTED_INTERFACES); - if (trustedInterfaces != null) { - ArrayList trustedInterfacesList = new ArrayList<>(); - if (trustedInterfaces instanceof ArrayList) { - trustedInterfacesList.addAll((ArrayList) trustedInterfaces); - } else if (trustedInterfaces instanceof String) { - trustedInterfacesList.add((String) trustedInterfaces); - } - for (String trustedInterface : trustedInterfacesList) { - multicastConfig.addTrustedInterface(trustedInterface.trim()); - } - } - if (log.isDebugEnabled()) { - log.debug("\n\tTrusted Interfaces: " + SecurityUtils.sanitize(multicastConfig.getTrustedInterfaces())); - } - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/error/OpenBankingErrorCodes.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/error/OpenBankingErrorCodes.java index e5955d44..1588349b 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/error/OpenBankingErrorCodes.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/error/OpenBankingErrorCodes.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -48,6 +48,9 @@ public class OpenBankingErrorCodes { public static final String MISSING_HEADER_PARAM_CLIENT_ID = "200015"; public static final String ERROR_IN_EVENT_POLLING_REQUEST = "200016"; + // Error titles + public static final String UNSUPPORTED_MEDIA_TYPE = "Unsupported Media Type"; + public static final String REGISTRATION_INTERNAL_ERROR = "Error occurred while registering application"; public static final String REGISTATION_DELETE_ERROR = "Error occurred while deleting application"; public static final String REGISTRATION_UPDATE_ERROR = "Error occurred while updating application"; diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/ApplicationIdentityService.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/ApplicationIdentityService.java index a416c685..8dd7171a 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/ApplicationIdentityService.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/ApplicationIdentityService.java @@ -36,10 +36,11 @@ public class ApplicationIdentityService { * Get JWKSet for application. * First checks to get from cache, else retrieve the JWKSet from the URL by calling * a method in JWKRetriever - * @param applicationName - * @param jwksUrl - * @param useCache + * @param applicationName Application Name + * @param jwksUrl URL of the JWKSet + * @param useCache Use cache or not * @return JWKSet + * @throws OpenBankingException if an error occurs while retrieving the JWKSet */ public JWKSet getPublicJWKSet(String applicationName, URL jwksUrl, boolean useCache) throws OpenBankingException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/cache/base/OpenBankingIdentityBaseCache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/cache/base/OpenBankingIdentityBaseCache.java index b434eb95..2f8776da 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/cache/base/OpenBankingIdentityBaseCache.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/cache/base/OpenBankingIdentityBaseCache.java @@ -25,8 +25,8 @@ /** * Cache definition to store objects in open banking iam component implementations. - * @param - * @param + * @param Extended Cache key + * @param Cache value */ public class OpenBankingIdentityBaseCache extends OpenBankingBaseCache { @@ -37,6 +37,7 @@ public class OpenBankingIdentityBaseCache /** * Initialize with unique cache name. + * @param cacheName Unique cache name */ public OpenBankingIdentityBaseCache(String cacheName) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/JWKRetriever.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/JWKRetriever.java index dba4f6a4..f0eff1db 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/JWKRetriever.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/JWKRetriever.java @@ -77,9 +77,9 @@ public JWKRetriever getInstance() { /** * Get JWK Set from remote resource retriever. * - * @param jwksURL - * @return - * @throws IOException + * @param jwksURL jwksURL in URL format + * @return JWKSet + * @throws OpenBankingException if an error occurs while retrieving resource */ public JWKSet updateJWKSetFromURL(URL jwksURL) throws OpenBankingException { @@ -105,7 +105,7 @@ public JWKSet updateJWKSetFromURL(URL jwksURL) throws OpenBankingException { * @param jwksURL jwksURL in URL format * @param applicationName application name as a string * @return jwkSet - * @throws OpenBankingException + * @throws OpenBankingException if an error occurs while getting JWK set */ public JWKSet getJWKSet(URL jwksURL , String applicationName) throws OpenBankingException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/ServerIdentityRetriever.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/ServerIdentityRetriever.java index e33c89a0..59d3f3b6 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/ServerIdentityRetriever.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/ServerIdentityRetriever.java @@ -118,7 +118,7 @@ public static Certificate getCertificate(String alias) throws KeyStoreException * Returns Signing certificate alias at Production environment. * @param certificateType Signing * @return String Certificate alias - * @throws OpenBankingException + * @throws OpenBankingException when there is an exception while retrieving the alias */ public static Optional getCertAlias(IdentityConstants.CertificateType certificateType) throws OpenBankingException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/sp/CommonServiceProviderRetriever.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/sp/CommonServiceProviderRetriever.java index 1eda4423..0281130d 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/sp/CommonServiceProviderRetriever.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/identity/retriever/sp/CommonServiceProviderRetriever.java @@ -47,7 +47,7 @@ public class CommonServiceProviderRetriever { * @param clientId ClientId of the application * @param property Property of the application * @return the property value from SP metadata - * @throws OpenBankingException + * @throws OpenBankingException if an error occurs while retrieving the property */ @Generated(message = "Excluding from code coverage since it requires a service call") public String getAppPropertyFromSPMetaData(String clientId, String property) throws OpenBankingException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/AnalyticsLogsUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/AnalyticsLogsUtils.java new file mode 100644 index 00000000..8a8c64de --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/AnalyticsLogsUtils.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.wso2.openbanking.accelerator.common.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Map; + +/** + * Open Banking common utility class to publish analytics logs. + */ +public class AnalyticsLogsUtils { + + private static final Log log = LogFactory.getLog(AnalyticsLogsUtils.class); + private static final String LOG_FORMAT = "Data Stream : %s , Data Stream Version : %s , Data : {\"payload\":%s}"; + private static final String DATA_PROCESSING_ERROR = "Error occurred while processing the analytics dataset"; + + /** + * Method to add analytics logs to the OB analytics log file. + * + * @param logFile Name of the logger which is used to log analytics data to the log file + * @param dataStream Name of the data stream to which the data belongs + * @param dataVersion Version of the data stream to which the data belongs + * @param analyticsData Data which belongs to the given data stream that needs to be logged via the given logger + * @throws OpenBankingException if an error occurs while processing the analytics data + */ + public static void addAnalyticsLogs(String logFile, String dataStream, String dataVersion, Map analyticsData) throws OpenBankingException { + Log customLog = LogFactory.getLog(logFile); + try { + customLog.info(String.format(LOG_FORMAT, dataStream, + dataVersion, new ObjectMapper().writeValueAsString(analyticsData))); + } catch (JsonProcessingException e) { + log.error(DATA_PROCESSING_ERROR); + throw new OpenBankingException(DATA_PROCESSING_ERROR, e); + } + } + +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/CertificateUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/CertificateUtils.java index e81f4109..65906695 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/CertificateUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/CertificateUtils.java @@ -43,8 +43,9 @@ public class CertificateUtils { /** * Parse the certificate content. * - * @param content the content to be pased - * @throws OpenBankingException + * @param content the content to be passed + * @return the parsed certificate + * @throws OpenBankingException if an error occurs while parsing the certificate */ public static X509Certificate parseCertificate(String content) throws OpenBankingException { @@ -82,4 +83,23 @@ private static String removeIllegalBase64Characters(String value) { // remove spaces, \r, \\r, \n, \\n, ], [ characters from certificate string return value.replaceAll("\\\\r|\\\\n|\\r|\\n|\\[|]| ", StringUtils.EMPTY); } + + /** + * Check whether the certificate is expired. + * + * @param peerCertificate the certificate to be checked + * @return true if the certificate is expired + */ + public static boolean isExpired(X509Certificate peerCertificate) { + try { + peerCertificate.checkValidity(); + } catch (CertificateException e) { + log.error("Certificate with the serial number " + + peerCertificate.getSerialNumber() + " issued by the CA " + + peerCertificate.getIssuerDN().toString() + " is expired. Caused by, " + e.getMessage()); + return true; + } + return false; + } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ErrorConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ErrorConstants.java index 7f3ce859..81106f21 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ErrorConstants.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ErrorConstants.java @@ -1,13 +1,13 @@ /** * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * + *

* WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * 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 @@ -15,6 +15,7 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.common.util; /** @@ -48,12 +49,19 @@ public class ErrorConstants { public static final String PATH_CREDIT_ACCOUNT_IDENTIFICATION = "Data.Initiation.CreditorAccount.Identification"; public static final String PATH_CREDIT_ACCOUNT_SCHEME = "Data.Initiation.CreditorAccount.SchemeName"; - public static final String PATH_INVALID = "Request path invalid"; public static final String PAYLOAD_INVALID = "Consent validation failed due to invalid initiation payload"; public static final String NOT_JSON_OBJECT_ERROR = "Payload is not a JSON object"; public static final String PAYLOAD_FORMAT_ERROR = "Request Payload is not in correct JSON format"; + public static final String PAYLOAD_FORMAT_ERROR_VALID_TO_DATE = "Invalid valid_to_date parameter in the payload" + + "for valid to date"; + public static final String PAYLOAD_FORMAT_ERROR_DEBTOR_ACC = "Parameter Debtor Account does not exists "; + public static final String PAYLOAD_FORMAT_ERROR_CREDITOR_ACC = "Parameter Creditor Account " + + "does not exists "; public static final String INVALID_REQ_PAYLOAD = "Invalid request payload"; + public static final String INVALID_REQ_PAYLOAD_INITIATION = "Invalid request payload in initiation key"; + public static final String INVALID_REQ_PAYLOAD_CONTROL_PARAMETERS = "Invalid request payload in " + + "control parameter key"; public static final String MISSING_DEBTOR_ACC_SCHEME_NAME = "Mandatory parameter Debtor Account Scheme Name does " + "not exists"; public static final String MISSING_DEBTOR_ACC_IDENTIFICATION = "Mandatory parameter Debtor Account Identification" + @@ -108,6 +116,7 @@ public class ErrorConstants { public static final String PATH_CONSENT_ID = "Data.Initiation.Consent-id"; public static final String PATH_DATA = "Data"; public static final String PATH_INITIATION = "Data.Initiation"; + public static final String PATH_CONTROL_PARAMETERS = "Data.ControlParameters"; public static final String PATH_RISK = "Data.Risk"; public static final String PATH_URL = "Data.Url"; public static final String PATH_EXPIRATION_DATE = "Data.Expiration-Date"; @@ -120,7 +129,6 @@ public class ErrorConstants { public static final String STATE_INVALID_ERROR = "Consent not in authorizable state"; public static final String DATE_PARSE_MSG = "Parsed OffsetDateTime: %s, current OffsetDateTime: %s"; public static final String EXP_DATE_PARSE_ERROR = "Error occurred while parsing the expiration date. "; - public static final String ACC_CONSENT_RETRIEVAL_ERROR = "Error occurred while retrieving the account initiation" + " request details"; public static final String CONSENT_EXPIRED = "Provided consent is expired"; @@ -134,7 +142,7 @@ public class ErrorConstants { + ErrorConstants.PATH_ACCESS_TOKEN; public static final String PATH_ACCESS_TOKEN = "Header.AccessToken"; public static final String MSG_INVALID_CLIENT_ID = "The client Id related the consent does not match with the " + - "client id bound to token:" + ErrorConstants.PATH_CLIENT_ID; + "client id bound to token"; public static final String PATH_CLIENT_ID = "Header.Client-id"; public static final String UNEXPECTED_ERROR = "OB.UnexpectedError"; public static final String INVALID_CONSENT_TYPE = "Invalid Consent Type found in the request"; @@ -154,62 +162,51 @@ public class ErrorConstants { "initiated amount:" + ErrorConstants.PATH_INSTRUCTED_AMOUNT_AMOUNT; public static final String PATH_INSTRUCTED_AMOUNT_AMOUNT = "Data.Initiation.InstructedAmount.Amount"; public static final String INSTRUCTED_AMOUNT_AMOUNT_NOT_FOUND = "Instructed Amount Amount isn't present in the " + - "payload:" + ErrorConstants.PATH_INSTRUCTED_AMOUNT; + "payload:"; public static final String INSTRUCTED_AMOUNT_CURRENCY_MISMATCH = "Instructed Amount currency does not match the " + "initiated amount or currency:" + ErrorConstants.PATH_INSTRUCTED_AMOUNT_CURRENCY; public static final String PATH_INSTRUCTED_AMOUNT_CURRENCY = "Data.Initiation.InstructedAmount.Currency"; public static final String INSTRUCTED_AMOUNT_CURRENCY_NOT_FOUND = "Instructed Amount Currency isn't present in " + - "the payload:" + ErrorConstants.PATH_INSTRUCTED_AMOUNT; - public static final String INSTRUCTED_AMOUNT_NOT_FOUND = "Instructed Amount isn't present in the payload:" + - ErrorConstants.PATH_INSTRUCTED_AMOUNT; - public static final String CREDITOR_ACC_SCHEME_NAME_MISMATCH = "Creditor Accounts Scheme does not match:" + - ErrorConstants.PATH_CREDIT_ACCOUNT_SCHEME; + "the payload:"; + public static final String INSTRUCTED_AMOUNT_NOT_FOUND = "Instructed Amount isn't present in the payload"; + public static final String CREDITOR_ACC_SCHEME_NAME_MISMATCH = "Creditor Accounts Scheme does not match"; public static final String CREDITOR_ACC_SCHEME_NAME_NOT_FOUND = "Creditor Accounts Scheme isn't present in the" + - " request or in the consent.:" + ErrorConstants.PATH_CREDIT_ACCOUNT_SCHEME; - public static final String CREDITOR_ACC_IDENTIFICATION_MISMATCH = "Creditor Account Identification does not match:" - + ErrorConstants.PATH_CREDIT_ACCOUNT_IDENTIFICATION; + " request or in the consent."; + public static final String CREDITOR_ACC_IDENTIFICATION_MISMATCH = "Creditor Account Identification does not match"; public static final String CREDITOR_ACC_IDENTIFICATION_NOT_FOUND = "Creditor Account Identification isn't " + - "present in the request or in the consent.:" + ErrorConstants.PATH_CREDIT_ACCOUNT_IDENTIFICATION; - public static final String CREDITOR_ACC_NAME_MISMATCH = "Creditor Account Name does not match:" + - ErrorConstants.PATH_CREDIT_ACCOUNT_NAME; + "present in the request or in the consent."; + public static final String CREDITOR_ACC_NAME_MISMATCH = "Creditor Account Name does not match"; public static final String CREDITOR_ACC_SEC_IDENTIFICATION_MISMATCH = "Creditor Account Secondary Identification" + - " does not match:" + ErrorConstants.PATH_CREDIT_ACCOUNT_SEC_IDENTIFICATION; + " does not match"; - public static final String DEBTOR_ACC_SCHEME_NAME_MISMATCH = "Debtor Account Scheme name does not " + - "match:" + ErrorConstants.PATH_DEBTOR_ACCOUNT_SCHEME; + public static final String DEBTOR_ACC_SCHEME_NAME_MISMATCH = "Debtor Account Scheme name does not "; public static final String DEBTOR_ACC_SCHEME_NAME_NOT_FOUND = "Debtor Account Scheme name isn't present in the " + - "request or in the consent:" + ErrorConstants.PATH_DEBTOR_ACCOUNT_SCHEME; + "request or in the consent"; public static final String DEBTOR_ACC_IDENTIFICATION_MISMATCH = "Debtor Account Identification does " + - "not match:" + ErrorConstants.PATH_DEBTOR_ACCOUNT_IDENTIFICATION; + "not match:"; public static final String DEBTOR_ACC_IDENTIFICATION_NOT_FOUND = "Debtor Account Identification isn't present " + - "in the request or in the consent:" + ErrorConstants.PATH_DEBTOR_ACCOUNT_IDENTIFICATION; - public static final String DEBTOR_ACC_NAME_MISMATCH = "Debtor Account Name does not match:" + - ErrorConstants.PATH_DEBTOR_ACCOUNT_NAME; + "in the request or in the consent"; + public static final String DEBTOR_ACC_NAME_MISMATCH = "Debtor Account Name does not match"; public static final String DEBTOR_ACC_SEC_IDENTIFICATION_MISMATCH = "Debtor Account Secondary Identification" + - " does not match:" + ErrorConstants.PATH_DEBTOR_ACCOUNT_SECOND_IDENTIFICATION; + " does not match"; public static final String PATH_DEBTOR_ACCOUNT_SECOND_IDENTIFICATION = "Data.Initiation.DebtorAccount.SecondaryIdentification"; - public static final String CREDITOR_ACC_NOT_FOUND = "Creditor Account isn't present in the request.:" + - ErrorConstants.PATH_CREDIT_ACCOUNT; - public static final String DEBTOR_ACC_MISMATCH = "Debtor Account isn't present in the request " + - "or in the consent:" + ErrorConstants.PATH_DEBTOR_ACCOUNT; - public static final String LOCAL_INSTRUMENT_MISMATCH = "Local Instrument Does Not Match:" + + public static final String CREDITOR_ACC_NOT_FOUND = "Creditor Account isn't present in the request."; + public static final String DEBTOR_ACC_MISMATCH = "Debtor Account mismatch"; + public static final String LOCAL_INSTRUMENT_MISMATCH = "Local Instrument Does Not Match" + ErrorConstants.PATH_LOCAL_INSTRUMENT; public static final String TOKEN_REVOKE_ERROR = "Token revocation unsuccessful. :" + ErrorConstants.PATH_CUTOFF_DATE; public static final String CUT_OFF_DATE_ELAPSED = "Cut off time has elapsed :" + ErrorConstants.PATH_CUTOFF_DATE; public static final String MSG_INVALID_CONSENT_ID = "The requested consent-Id does not match with the consent-Id" + - " bound to token:" + ErrorConstants.PATH_CONSENT_ID; + " bound to token"; public static final String PAYMENT_CONSENT_STATE_INVALID = "Payment validation failed due to invalid consent" + - " state.:" + ErrorConstants.PATH_STATUS; - public static final String DATA_NOT_FOUND = "Data is not found or empty in the request.:" + - ErrorConstants.PATH_DATA; - public static final String INITIATION_NOT_FOUND = "Initiation is not found or empty in the request.:" + - ErrorConstants.PATH_INITIATION; - public static final String RISK_MISMATCH = "RISK Does Not Match.:" + ErrorConstants.PATH_RISK; - public static final String RISK_NOT_FOUND = "RISK is not found or empty in the request.:" + - ErrorConstants.PATH_RISK; + " state."; + public static final String VRP_CONSENT_STATUS_INVALID = "Validation failed due to invalid consent status."; + public static final String DATA_NOT_FOUND = "Data is not found or empty in the request."; + public static final String INITIATION_NOT_FOUND = "Initiation is not found or is empty in the request."; + public static final String RISK_MISMATCH = "RISK Does Not Match."; public static final String INVALID_URI_ERROR = "Path requested is invalid. :" + ErrorConstants.PATH_URL; public static final String COF_CONSENT_STATE_INVALID = "Confirmation of Funds validation failed due to invalid" + " consent state.:" + ErrorConstants.PATH_STATUS; @@ -221,9 +218,127 @@ public class ErrorConstants { " retrieval request"; public static final String INVALID_CONSENT_ID = "Invalid Consent Id found in the request"; public static final String CONSENT_ID_NOT_FOUND = "Consent ID not available in consent data"; - public static final String FIELD_INVALID_DATE = "OB.Field.InvalidDate"; public static final String EXPIRED_DATE_ERROR = "The ExpirationDateTime value has to be a future date."; + public static final String CONSENT_ATTRIBUTE_RETRIEVAL_ERROR = "Error occurred while retrieving the consent " + + "attributes"; + + // VRP error constants + + public static final String VRP_INITIATION_HANDLE_ERROR = "Error occurred while handling the VRP " + + "initiation request"; + public static final String VRP_INITIATION_RETRIEVAL_ERROR = "Error occurred while handling the VRP initiation" + + " retrieval request"; + public static final String PAYLOAD_FORMAT_ERROR_VALID_FROM_DATE = "Request Payload is not in correct JSON format" + + " for valid from date"; + public static final String INVALID_VALID_TO_DATE_TIME = "Invalid date time format in validToDateTime"; + public static final String INVALID_VALID_FROM_DATE_TIME = "Invalid date time format in validFromDateTime"; + public static final String PAYLOAD_FORMAT_ERROR_CONTROL_PARAMETER = "Request Payload is not in correct JSON " + + "format for control parameter key"; + public static final String PAYLOAD_FORMAT_ERROR_MAXIMUM_INDIVIDUAL_AMOUNT = "Invalid maximum individual amount"; + public static final String MISSING_MAXIMUM_INDIVIDUAL_AMOUNT = "Missing mandatory parameter Maximum Individual" + + " Amount"; + public static final String PAYLOAD_FORMAT_ERROR_MAXIMUM_INDIVIDUAL_CURRENCY = "Invalid maximum individual amount" + + "currency"; + public static final String PAYLOAD_FORMAT_ERROR_INITIATION = "Missing mandatory parameter Initiation" + + " in the payload"; + public static final String PAYLOAD_FORMAT_ERROR_RISK = "Mandatory parameter Risk does not exists" + + " in the payload"; + public static final String INVALID_PERIOD_TYPE = "Invalid value for period type in PeriodicLimits"; + public static final String INVALID_PARAMETER = "Parameter passed in is null "; + public static final String INVALID_CLIENT_ID_MATCH = "Consent validation failed due to client ID mismatch"; + public static final String INVALID_DATE_TIME_FORMAT = "Date and Time is not in correct JSON " + + "ISO-8601 date-time format"; + public static final String MISSING_DATE_TIME_FORMAT = "The value is empty or the value is not a string"; + public static final String MISSING_VALID_TO_DATE_TIME = "Missing parameter ValidToDateTime"; + public static final String MISSING_VALID_FROM_DATE_TIME = "Missing parameter ValidFromDateTime"; + public static final String INVALID_PARAMETER_PERIODIC_LIMITS = "Parameter passed in is null , " + + "empty or not a JSONArray"; + public static final String MISSING_PERIOD_LIMITS = "Mandatory parameter " + + "periodic limits is missing in the payload"; + public static final String MISSING_PERIOD_TYPE = "Missing required parameter Period type"; + public static final String PAYLOAD_FORMAT_ERROR_PERIODIC_LIMITS_PERIOD_TYPE = "Value of period type is empty or " + + "the value passed in is not a string"; + public static final String PAYLOAD_FORMAT_ERROR_PERIODIC_LIMITS_ALIGNMENT = "Value of periodic alignment is empty" + + " or the value passed in is not a string"; + public static final String MISSING_PERIOD_ALIGNMENT = "Missing periodic alignment in periodic limits"; + public static final String INVALID_PERIOD_ALIGNMENT = "Invalid value for period alignment in PeriodicLimits"; + public static final String INVALID_PARAMETER_MESSAGE = "Parameter '%s' passed in is null, empty, or not a %s"; + public static final String DATE_INVALID_PARAMETER_MESSAGE = "Invalid date-time range for ValidToDateTime "; + public static final String INVALID_PERIODIC_LIMIT_SIZE = "Periodic limits exceed the allowed limits"; + public static final String DUPLICATE_PERIOD_TYPE = "Duplicate Period Types found in the request"; + public static final String CURRENCY_MISMATCH = "Currency does not match with the currency of the periodic limits"; + public static final int MAXIMUM_PERIODIC_LIMITS = 6; + public static final String INVALID_MAXIMUM_INDIVIDUAL_CURRENCY = "Invalid value for Currency in " + + "MaximumIndividualAmount"; + public static final String INVALID_PERIODIC_LIMIT_AMOUNT = "Invalid value for in Amount in Periodic Limits"; + public static final String INVALID_PERIODIC_LIMIT_CURRENCY = "Invalid value for Currency in Periodic Limits"; + + + // vrp path parameters + public static final String PATH_VALID_TO_DATE = "Data.ControlParameters.ValidToDateTime"; + public static final String PATH_VALID_FROM_DATE = "Data.ControlParameters.ValidFromDateTime"; + public static final String PATH_MAXIMUM_INDIVIDUAL_AMOUNT = "Data.ControlParameters.MaximumIndividualAmount"; + public static final String PATH_PERIOD_LIMIT = "Data.ControlParameters.PeriodicLimits"; + public static final String PATH_PERIOD_LIMIT_AMOUNT = "Data.ControlParameters.PeriodicLimits.Amount"; + public static final String PATH_PERIOD_LIMIT_CURRENCY = "Data.ControlParameters.PeriodicLimits.Currency"; + public static final String PATH_PERIOD_TYPE = "Data.ControlParameters.PeriodicLimits.PeriodType"; + public static final String PATH_PERIOD_ALIGNMENT = "Data.ControlParameters.PeriodicLimits.PeriodAlignment"; + + // VRP Authorization flow + public static final String CONTROL_PARAMETERS_MISSING_ERROR = "Missing mandatory parameter the ControlParameters"; + public static final String DATA_OBJECT_MISSING_ERROR = "Missing mandatory parameter the Data"; + public static final String MAX_AMOUNT_NOT_JSON_OBJECT_ERROR = "Parameter Maximum Individual Amount is" + + "not of type JSONObject"; + public static final String NOT_JSON_ARRAY_ERROR = "Parameter PeriodicLimits is not a JSON Array"; + public static final String PERIOD_ALIGNMENT_NOT_STRING_ERROR = "Parameter Period Alignment is not a String"; + public static final String PERIOD_TYPE_NOT_STRING_ERROR = "Parameter Period Type is not a String"; + public static final String NOT_STRING_ERROR = "Parameter amount or currency is not a String"; + // VRP Submission flow + public static final String REMITTANCE_INFO_NOT_FOUND = "Remittance info is not present in the request."; + public static final String INSTRUCTION_IDENTIFICATION_NOT_FOUND = "Instruction Identification isn't present" + + " in the request"; + public static final String END_TO_END_IDENTIFICATION_PARAMETER_NOT_FOUND = "End to End Identification isn't" + + " present in the request"; + public static final String RISK_PARAMETER_MISMATCH = "RISK does not match"; + public static final String INSTRUCTED_AMOUNT_PARAMETER_NOT_FOUND = "Instructed Amount isn't present in the payload"; + public static final String INITIATION_REMITTANCE_INFO_PARAMETER_NOT_FOUND = "Remittance ifo present under" + + " initiation isn't present in the request"; + public static final String INSTRUCTION_REMITTANCE_INFO_PARAMETER_NOT_FOUND = "Remittance ifo present under" + + " instruction isn't present in the request"; + public static final String REMITTANCE_INFO_MISMATCH = "Remittance info does not match"; + public static final String REMITTANCE_UNSTRUCTURED_MISMATCH = "Remittance Information Unstructured does not " + + "match"; + public static final String INVALID_SUBMISSION_TYPE = "Value associated with INSTRUCTION_IDENTIFICATION key is " + + "not a String instance"; + public static final String INVALID_END_TO_END_IDENTIFICATION_TYPE = "Value associated with" + + " END_TO_END_IDENTIFICATION key is not a String instance"; + public static final String RISK_NOT_FOUND = "Risk is not found or empty in the request."; + public static final String RISK_NOT_JSON_ERROR = "Risk parameter is not in the correct JSON format"; + public static final String INSTRUCTION_NOT_FOUND = "Instruction is not found or empty in the request."; + public static final String INVALID_REQUEST_CONSENT_ID = "The consent-Id is not present in the request" + + " or it is not a String instance or there is a consentId mismatch"; + public static final String INSTRUCTION_CREDITOR_ACC_NOT_JSON_ERROR = "Creditor Account present under instruction" + + " isn't present in the correct JSON format in the request."; + public static final String INITIATION_CREDITOR_ACC_NOT_JSON_ERROR = "Creditor Account present under initiation" + + " isn't present in the correct JSON format in the request."; + public static final String DEBTOR_ACC_NOT_JSON_ERROR = "Debtor Account isn't present in the correct JSON format " + + "in the request."; + public static final String INITIATION_REMITTANCE_INFO_NOT_JSON_ERROR = "Remittance info of initiation is not " + + "present in the correct JSON format in the request."; + public static final String INSTRUCTION_REMITTANCE_INFO_NOT_JSON_ERROR = "Remittance info of instruction is not" + + " present in the correct JSON format in the request."; + public static final String DEBTOR_ACC_NOT_FOUND = "Debtor Account isn't present in the request."; + public static final String DATA_NOT_JSON_ERROR = "Data parameter is not in the correct JSON format in the request"; + public static final String INSTRUCTED_AMOUNT_NOT_STRING = "Value associated with Amount key is " + + "not a String instance"; + public static final String INSTRUCTED_AMOUNT_CURRENCY_NOT_STRING = "Value associated with Currency key is " + + "not a String instance"; + public static final String INSTRUCTED_AMOUNT_NOT_JSON_ERROR = "Instructed Amount is not in the correct JSON " + + "format in the request"; + public static final String INITIATION_NOT_JSON = "Initiation is not in the correct JSON " + + "format in the request"; + public static final String INSTRUCTION_NOT_JSON = "Instruction is not in the correct JSON format in the request"; } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/HTTPClientUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/HTTPClientUtils.java index 37996812..5e84500f 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/HTTPClientUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/HTTPClientUtils.java @@ -66,6 +66,7 @@ public class HTTPClientUtils { * @return Closeable https client * @throws OpenBankingException OpenBankingException exception */ + @Generated(message = "Ignoring because ServerConfiguration cannot be mocked") public static CloseableHttpClient getHttpsClient() throws OpenBankingException { SSLConnectionSocketFactory sslsf = createSSLConnectionSocketFactory(); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/JWTUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/JWTUtils.java index 1489f035..172033df 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/JWTUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/JWTUtils.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -20,6 +20,8 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSObject; +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jose.jwk.source.RemoteJWKSet; import com.nimbusds.jose.proc.BadJOSEException; import com.nimbusds.jose.proc.JWSKeySelector; @@ -33,11 +35,23 @@ import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; import com.nimbusds.jwt.proc.DefaultJWTProcessor; import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; import net.minidev.json.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.net.MalformedURLException; import java.net.URL; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; import java.text.ParseException; +import java.util.Base64; +import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -46,6 +60,9 @@ */ public class JWTUtils { + private static final Log log = LogFactory.getLog(JWTUtils.class); + private static final String RS = "RS"; + private static final String ALGORITHM_RSA = "RSA"; /** * Decode request JWT. @@ -53,6 +70,7 @@ public class JWTUtils { * @param jwtToken jwt sent by the tpp * @param jwtPart expected jwt part (header, body) * @return json object containing requested jwt part + * @throws ParseException if an error occurs while parsing the jwt */ public static JSONObject decodeRequestJWT(String jwtToken, String jwtPart) throws ParseException { @@ -77,6 +95,10 @@ public static JSONObject decodeRequestJWT(String jwtToken, String jwtPart) throw * @param jwksUri endpoint displaying the key set for the signing certificates * @param algorithm the signing algorithm for jwt * @return true if signature is valid + * @throws ParseException if an error occurs while parsing the jwt + * @throws BadJOSEException if the jwt is invalid + * @throws JOSEException if an error occurs while processing the jwt + * @throws MalformedURLException if an error occurs while creating the URL object */ @Generated(message = "Excluding from code coverage since can not call this method due to external https call") public static boolean validateJWTSignature(String jwtString, String jwksUri, String algorithm) @@ -115,4 +137,118 @@ public static boolean validateJWTSignature(String jwtString, String jwksUri, Str return true; } + /** + * Validates the signature of a given JWT against a given public key. + * + * @param signedJWT the signed JWT to be validated + * @param publicKey the public key that is used for validation + * @return true if signature is valid else false + * @throws NoSuchAlgorithmException if the given algorithm doesn't exist + * @throws InvalidKeySpecException if the provided key is invalid + * @throws JOSEException if an error occurs during the signature validation process + */ + @Generated(message = "Excluding from code coverage as KeyFactory does not initialize in testsuite") + public static boolean isValidSignature(SignedJWT signedJWT, String publicKey) + throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException, OpenBankingException { + + byte[] publicKeyData = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyData); + // Example : RS256 + String algorithm = signedJWT.getHeader().getAlgorithm().getName(); + KeyFactory kf = getKeyFactory(algorithm); + RSAPublicKey rsapublicKey = (RSAPublicKey) kf.generatePublic(spec); + JWSVerifier verifier = new RSASSAVerifier(rsapublicKey); + return signedJWT.verify(verifier); + } + + /** + * Validate legitimacy of a JWS. + * + * @param jwsString JWT string + * @return true if a given jwsString adheres a valid JWS Format + */ + public static boolean isValidJWSFormat(String jwsString) { + + return StringUtils.isBlank(jwsString) ? false : + StringUtils.countMatches(jwsString, OpenBankingConstants.DOT_SEPARATOR) == 2; + } + + /** + * Parses the provided JWT string into a SignedJWT object. + * + * @param jwtString the JWT string to parse + * @return the parsed SignedJWT object + * @throws IllegalArgumentException if the provided token identifier is not a parsable JWT + * + */ + public static SignedJWT getSignedJWT(String jwtString) throws ParseException { + + if (isValidJWSFormat(jwtString)) { + return SignedJWT.parse(jwtString); + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("Provided token identifier is not a parsable JWT: %s", jwtString)); + } + throw new IllegalArgumentException("Provided token identifier is not a parsable JWT."); + } + } + + /** + * Checks if the given expiration time is valid based on the current system time and a default time skew. + * + * @param defaultTimeSkew defaultTimeSkew to adjust latency issues. + * @param expirationTime the exp of the jwt that should be validated. + * @return True if the expiration time is valid considering the default time skew; false otherwise. + */ + public static boolean isValidExpiryTime(Date expirationTime, long defaultTimeSkew) { + + if (expirationTime != null) { + long timeStampSkewMillis = defaultTimeSkew * 1000; + long expirationTimeInMillis = expirationTime.getTime(); + long currentTimeInMillis = System.currentTimeMillis(); + return (currentTimeInMillis + timeStampSkewMillis) <= expirationTimeInMillis; + } else { + return false; + } + } + + /** + * Checks if the given "not before" time is valid based on the current system time and a default time skew. + * + * @param defaultTimeSkew defaultTimeSkew to adjust latency issues. + * @param notBeforeTime nbf of the jwt that should be validated + * @return True if the "not before" time is valid considering the default time skew; false otherwise. + */ + public static boolean isValidNotValidBeforeTime(Date notBeforeTime, long defaultTimeSkew) { + + if (notBeforeTime != null) { + long timeStampSkewMillis = defaultTimeSkew * 1000; + long notBeforeTimeMillis = notBeforeTime.getTime(); + long currentTimeInMillis = System.currentTimeMillis(); + return currentTimeInMillis + timeStampSkewMillis >= notBeforeTimeMillis; + } else { + return false; + } + } + + /** + * Returns a KeyFactory instance for the specified algorithm. + * + * @param algorithm the algorithm name, such as "RS256". + * @return the KeyFactory instance. + * @throws OpenBankingException if the provided algorithm is not supported. + * @throws NoSuchAlgorithmException if the specified algorithm is invalid. + */ + @Generated(message = "Excluding from code coverage as KeyFactory does not initialize in testsuite") + private static KeyFactory getKeyFactory(String algorithm) throws OpenBankingException, NoSuchAlgorithmException { + + // In here if the algorithm is directly passes (like RS256) it will generate exceptions + // hence Base algorithm should be passed (Example: RSA) + if (algorithm.indexOf(RS) == 0) { + return KeyFactory.getInstance(ALGORITHM_RSA); + } else { + throw new OpenBankingException("Algorithm " + algorithm + " not yet supported."); + } + } } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/OpenBankingUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/OpenBankingUtils.java index 3f19f805..98593449 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/OpenBankingUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/OpenBankingUtils.java @@ -18,12 +18,16 @@ package com.wso2.openbanking.accelerator.common.util; import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; import com.wso2.openbanking.accelerator.common.exception.OpenBankingRuntimeException; +import com.wso2.openbanking.accelerator.common.identity.IdentityConstants; +import net.minidev.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.lang.reflect.InvocationTargetException; +import java.text.ParseException; /** * Open Banking common utility class. @@ -53,6 +57,33 @@ public static Object getClassInstanceFromFQN(String classpath) { } } + /** + * Extract software_environment (SANDBOX or PRODUCTION) from SSA. + * + * @param softwareStatement software statement (jwt) extracted from request payload + * @return software_environment + * @throws ParseException if an error occurs while parsing the software statement + */ + public static String getSoftwareEnvironmentFromSSA(String softwareStatement) throws ParseException { + + if (StringUtils.isEmpty(softwareStatement)) { + return IdentityConstants.PRODUCTION; + } + + final JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, + OpenBankingConstants.JWT_BODY); + // Retrieve the SSA property name used for software environment identification + final String sandboxEnvIdentificationPropertyName = OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyName(); + // Retrieve the expected value for the sandbox environment + final String sandboxEnvIdentificationValue = OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyValueForSandbox(); + return sandboxEnvIdentificationValue.equalsIgnoreCase(softwareStatementBody + .getAsString(sandboxEnvIdentificationPropertyName)) + ? IdentityConstants.SANDBOX + : IdentityConstants.PRODUCTION; + } + /** * Method to obtain boolean value for check if the Dispute Resolution Data is publishable. * @@ -70,10 +101,11 @@ public static boolean isPublishableDisputeData(int statusCode) { } /** - * Method to reduce string length + * Method to reduce string length. * - * @param input and maxLength for dispute data - * @return String + * @param input Input for dispute data + * @param maxLength Max length for dispute data + * @return String with reduced length */ public static String reduceStringLength(String input, int maxLength) { if (StringUtils.isEmpty(input) || input.length() <= maxLength) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/SPQueryExecutorUtil.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/SPQueryExecutorUtil.java index ca479c46..72c83d1c 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/SPQueryExecutorUtil.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/SPQueryExecutorUtil.java @@ -48,11 +48,15 @@ public class SPQueryExecutorUtil { /** * Executes the given query in SP. * - * @param appName Name of the siddhi app. - * @param query Name of the query + * @param appName Name of the siddhi app. + * @param query Name of the query + * @param spUserName Username for SP + * @param spPassword Password for SP + * @param spApiHost Hostname of the SP * @return JSON object with result - * @throws IOException IO Exception. - * @throws ParseException Parse Exception. + * @throws IOException IO Exception. + * @throws ParseException Parse Exception. + * @throws OpenBankingException OpenBanking Exception. */ public static JSONObject executeQueryOnStreamProcessor(String appName, String query, String spUserName, String spPassword, String spApiHost) diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ServiceProviderUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ServiceProviderUtils.java index 4a94f93f..fae34feb 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ServiceProviderUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/ServiceProviderUtils.java @@ -32,7 +32,7 @@ public class ServiceProviderUtils { * Get Tenant Domain String for the client id. * @param clientId the client id of the application * @return tenant domain of the client - * @throws OpenBankingException + * @throws OpenBankingException if an error occurs while retrieving the tenant domain */ @Generated(message = "Ignoring because OAuth2Util cannot be mocked with no constructors") public static String getSpTenantDomain(String clientId) throws OpenBankingException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/eidas/certificate/extractor/common/PSPRole.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/eidas/certificate/extractor/common/PSPRole.java index fad88f1f..6ec64070 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/eidas/certificate/extractor/common/PSPRole.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/util/eidas/certificate/extractor/common/PSPRole.java @@ -21,6 +21,7 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1UTF8String; import org.bouncycastle.asn1.DERUTF8String; import java.util.ArrayList; @@ -56,7 +57,7 @@ public static List getInstance(ASN1Encodable asn1Encodable) { Iterator it = sequence.iterator(); while (it.hasNext()) { ASN1ObjectIdentifier objectIdentifier = ASN1ObjectIdentifier.getInstance(it.next()); - DERUTF8String instance = DERUTF8String.getInstance(it.next()); + ASN1UTF8String instance = DERUTF8String.getInstance(it.next()); pspRoleList.add(Arrays.stream(PSPRole.values()) .filter(role -> role.getPspRoleOid().equals(objectIdentifier.getId()) diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/validator/OpenBankingValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/validator/OpenBankingValidator.java index fc38a601..44c60e32 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/validator/OpenBankingValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/main/java/com/wso2/openbanking/accelerator/common/validator/OpenBankingValidator.java @@ -57,6 +57,9 @@ public static OpenBankingValidator getInstance() { /** * Check for violations on request object. Stop at the first violation and return error. * Validations are executed based on annotation in model of the class. + * + * @param object Object to be validated + * @return Error message if there is a violation, null otherwise */ public String getFirstViolation(Object object) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/OBConfigParserTests.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/OBConfigParserTests.java index a4b542b2..44d6d038 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/OBConfigParserTests.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/OBConfigParserTests.java @@ -425,6 +425,8 @@ public void testIsNonErrorDisputeDataPublishingEnabled() { Assert.assertTrue(isEnabled); } + + @Test (priority = 33) public void testRealtimeEventNotificationConfigs() { String dummyConfigFile = absolutePathForTestResources + "/open-banking.xml"; OpenBankingConfigParser openBankingConfigParser = OpenBankingConfigParser.getInstance(dummyConfigFile); @@ -446,4 +448,23 @@ public void testRealtimeEventNotificationConfigs() { } + @Test (priority = 34) + public void testIsConsentAmendmentHistoryEnabled() { + + String dummyConfigFile = absolutePathForTestResources + "/open-banking.xml"; + boolean isEnabled = OpenBankingConfigParser.getInstance(dummyConfigFile) + .isConsentAmendmentHistoryEnabled(); + + Assert.assertTrue(isEnabled); + } + + @Test (priority = 35) + public void testGetOBKeyManagerExtensionImpl() { + + String dummyConfigFile = absolutePathForTestResources + "/open-banking.xml"; + String className = OpenBankingConfigParser.getInstance(dummyConfigFile) + .getOBKeyManagerExtensionImpl(); + + Assert.assertEquals(className, "com.wso2.openbanking.accelerator.keymanager.OBKeyManagerImpl"); + } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheMulticastTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheMulticastTest.java deleted file mode 100644 index 76cfa338..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheMulticastTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.test.distributed.caching; - -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedMember; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** - * Unit test for open banking distributed cache with Multicast discovery method. - */ -@PowerMockIgnore({"jdk.internal.reflect.*", "javax.management.*"}) -@PrepareForTest({OpenBankingConfigParser.class}) -public class OpenBankingDistributedCacheMulticastTest extends PowerMockTestCase { - - - private static TestOpenBankingDistributedCache cacheMulticast; - - @Mock - OpenBankingConfigParser openBankingConfigParser; - - - @BeforeClass - public void beforeTests() { - MockitoAnnotations.initMocks(this); - - Map configsMulticast = new HashMap<>(); - configsMulticast.put(OpenBankingDistributedCacheConstants.ENABLED, "true"); - configsMulticast.put(OpenBankingDistributedCacheConstants.HOST_NAME, "localhost"); - configsMulticast.put(OpenBankingDistributedCacheConstants.PORT, "5721"); - configsMulticast.put(OpenBankingDistributedCacheConstants.DISCOVERY_MECHANISM, "Multicast"); - configsMulticast.put(OpenBankingDistributedCacheConstants.MULTICAST_GROUP, "224.2.2.3"); - configsMulticast.put(OpenBankingDistributedCacheConstants.MULTICAST_PORT, "54321"); - ArrayList interfaces = new ArrayList<>(); - interfaces.add("192.168.1.100-110"); - configsMulticast.put(OpenBankingDistributedCacheConstants.TRUSTED_INTERFACES, interfaces); - configsMulticast.put(OpenBankingDistributedCacheConstants.PROPERTY_LOGGING_TYPE, "none"); - - Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configsMulticast); - - PowerMockito.mockStatic(OpenBankingConfigParser.class); - PowerMockito.when(OpenBankingConfigParser.getInstance()) - .thenReturn(openBankingConfigParser); - - cacheMulticast = new TestOpenBankingDistributedCache("test-cache-multicast"); - - } - - @Test(priority = 1) - public void addGetTestMulticast() { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheMulticast.addToCache(key, "cache-body"); - String fromCache = null; - if (!cacheMulticast.isEmpty()) { - fromCache = cacheMulticast.getFromCache(key); - } - - Assert.assertEquals(fromCache, "cache-body"); - } - - @Test(priority = 2) - public void removeTestMulticast() { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheMulticast.removeFromCache(key); - - String fromCache = cacheMulticast.getFromCache(key); - - Assert.assertNull(fromCache); - } - - @Test(priority = 3) - public void cacheEvictionTestMulticast() throws InterruptedException { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheMulticast.addToCache(key, "cache-body"); - TimeUnit.MINUTES.sleep(2); - - String fromCache = cacheMulticast.getFromCache(key); - Assert.assertNull(fromCache); - } - - @AfterClass - public void after() { - OpenBankingDistributedMember.of().shutdown(); - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheTCPTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheTCPTest.java deleted file mode 100644 index 0b65dae1..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/OpenBankingDistributedCacheTCPTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.test.distributed.caching; - -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedMember; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - - -/** - * Unit test for open banking distributed cache with TCP discovery method. - */ -@PowerMockIgnore({"jdk.internal.reflect.*", "javax.management.*"}) -@PrepareForTest({OpenBankingConfigParser.class}) -public class OpenBankingDistributedCacheTCPTest extends PowerMockTestCase { - - - private static TestOpenBankingDistributedCache cacheTCP; - - @Mock - OpenBankingConfigParser openBankingConfigParser; - - - @BeforeClass - public void beforeTests() { - MockitoAnnotations.initMocks(this); - - Map configsTCP = new HashMap<>(); - configsTCP.put(OpenBankingDistributedCacheConstants.ENABLED, "true"); - configsTCP.put(OpenBankingDistributedCacheConstants.HOST_NAME, "localhost"); - configsTCP.put(OpenBankingDistributedCacheConstants.PORT, "5721"); - configsTCP.put(OpenBankingDistributedCacheConstants.DISCOVERY_MECHANISM, "TCP"); - ArrayList members = new ArrayList<>(); - members.add("localhost:5722"); - configsTCP.put(OpenBankingDistributedCacheConstants.MEMBERS, members); - configsTCP.put(OpenBankingDistributedCacheConstants.PROPERTY_LOGGING_TYPE, "none"); - - Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configsTCP); - - PowerMockito.mockStatic(OpenBankingConfigParser.class); - PowerMockito.when(OpenBankingConfigParser.getInstance()) - .thenReturn(openBankingConfigParser); - - cacheTCP = new TestOpenBankingDistributedCache("test-cache-tcp"); - - } - - @Test(priority = 1) - public void addGetTestTCP() { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheTCP.addToCache(key, "cache-body"); - String fromCache = null; - if (!cacheTCP.isEmpty()) { - fromCache = cacheTCP.getFromCache(key); - } - - Assert.assertEquals(fromCache, "cache-body"); - } - - @Test(priority = 2) - public void removeTestTCP() { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheTCP.removeFromCache(key); - - String fromCache = cacheTCP.getFromCache(key); - - Assert.assertNull(fromCache); - } - - @Test(priority = 3) - public void cacheEvictionTestTCP() throws InterruptedException { - TestOpenBankingDistributedCacheKey key = new TestOpenBankingDistributedCacheKey("test-cache-key"); - cacheTCP.addToCache(key, "cache-body"); - TimeUnit.MINUTES.sleep(2); - - String fromCache = cacheTCP.getFromCache(key); - Assert.assertNull(fromCache); - } - - - @AfterClass - public void after() { - OpenBankingDistributedMember.of().shutdown(); - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCache.java deleted file mode 100644 index 01c5a027..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCache.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.common.test.distributed.caching; - -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCache; - -/** - * TestOpenBankingDistributedCache. - */ -public class TestOpenBankingDistributedCache - extends OpenBankingDistributedCache { - - int cacheTimeToLiveMinutes; - - /** - * Initialize With unique cache name. - * - * @param cacheName Name of the cache. - */ - public TestOpenBankingDistributedCache(String cacheName) { - super(cacheName); - setCacheTimeToLiveMinutes(); - } - - @Override - public int getCacheTimeToLiveMinutes() { - return this.cacheTimeToLiveMinutes; - } - - public void setCacheTimeToLiveMinutes() { - this.cacheTimeToLiveMinutes = 2; - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CertificateUtilsTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CertificateUtilsTest.java index 3d933d28..3cfb2c49 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CertificateUtilsTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CertificateUtilsTest.java @@ -21,6 +21,7 @@ import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; import com.wso2.openbanking.accelerator.common.util.CertificateUtils; import org.testng.Assert; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.security.cert.X509Certificate; @@ -30,6 +31,13 @@ */ public class CertificateUtilsTest { + private X509Certificate expiredX509Cert; + + @BeforeClass + public void init() throws OpenBankingException { + this.expiredX509Cert = CommonTestUtil.getExpiredSelfCertificate(); + } + @Test(description = "when valid transport cert, return x509 certificate") public void testParseCertificate() throws OpenBankingException { Assert.assertNotNull(CertificateUtils @@ -69,4 +77,10 @@ public void testIsExpired() throws OpenBankingException { Assert.assertNotNull(testCert); Assert.assertFalse(CommonTestUtil.hasExpired(testCert)); } + + @Test + public void testIsCertValidWithExpiredCert() { + Assert.assertTrue(CertificateUtils.isExpired(expiredX509Cert)); + } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CommonTestUtil.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CommonTestUtil.java index c44e0978..0d35ddec 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CommonTestUtil.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/CommonTestUtil.java @@ -18,6 +18,9 @@ package com.wso2.openbanking.accelerator.common.test.util; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.CertificateUtils; + import java.io.ByteArrayInputStream; import java.lang.reflect.Field; import java.security.cert.CertificateException; @@ -35,6 +38,7 @@ public class CommonTestUtil { public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; public static final String END_CERT = "-----END CERTIFICATE-----"; public static final String X509_CERT_INSTANCE_NAME = "X.509"; + private static X509Certificate expiredSelfCertificate = null; public static final String EIDAS_CERT = "-----BEGIN CERTIFICATE-----" + "MIIEjDCCA3SgAwIBAgILAKTSmx6PZuerUKkwDQYJKoZIhvcNAQELBQAwSDELMAkG" + "A1UEBhMCREUxDDAKBgNVBAoMA0JEUjERMA8GA1UECwwISVQgLSBEZXYxGDAWBgNV" + @@ -63,36 +67,34 @@ public class CommonTestUtil { "R783WZESc2tbq1LYOH5wNg==" + "-----END CERTIFICATE-----"; public static final String TEST_CLIENT_CERT = "-----BEGIN CERTIFICATE-----" + - "MIIFljCCA36gAwIBAgIJAN5zDsVzPq0aMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD" + - "VQQGEwJMSzELMAkGA1UECAwCV1AxDDAKBgNVBAcMA0NPTDEaMBgGA1UECgwRV1NP" + - "MiAoVUspIExJTUlURUQxFDASBgNVBAsMC09wZW5CYW5raW5nMS4wLAYDVQQDDCVP" + - "cGVuQmFua2luZyBQcmUtUHJvZHVjdGlvbiBJc3N1aW5nIENBMSAwHgYJKoZIhvcN" + - "AQkBFhFtYWxzaGFuaUB3c28yLmNvbTAeFw0yMjAxMTgwNzI3NDJaFw0yNDAxMTgw" + - "NzI3NDJaMHMxCzAJBgNVBAYTAkdCMRowGAYDVQQKDBFXU08yIChVSykgTElNSVRF" + - "RDErMCkGA1UEYQwiUFNER0ItT0ItVW5rbm93bjAwMTU4MDAwMDFIUVFyWkFBWDEb" + - "MBkGA1UEAwwSMDAxNTgwMDAwMUhRUXJaQUFYMIIBIjANBgkqhkiG9w0BAQEFAAOC" + - "AQ8AMIIBCgKCAQEA59+TouW8sLFWk7MUht40v+DDglinjL2qmQ+wP3YNtvza/7Ue" + - "KZ+gWw92jd0v99xZz7c5KOgtTgctAmIU1qjGLwzHzn/fl/ZrO4spGLIbU7RwGHA7" + - "BSpB4k0vGdpCBigaaILHhBrAczDJ1BLYMS4lg69+6fYTeY2s0Khv92NWl8TXorAH" + - "W0D8KrbZ3chWIynZamNu8KN6s+GL5jyu6pzJpXVNOXiUdRr4U9fLctw7qPw4RbBM" + - "edXohmVFwMTQ7lMKax+wHOjfQDQW7KuZxRRYiUqB3hjyhrKlIpjjWtnxLclymTAI" + - "TRMqFlH8KFq/rVBGQ8F3SnDp90E25RbSWdfNRwIDAQABo4HyMIHvMA4GA1UdDwEB" + - "/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHQYDVR0OBBYE" + - "FNxNxhzaeU3VdIMlXkNiYbnjheOnMIGeBggrBgEFBQcBAwSBkTCBjjATBgYEAI5G" + - "AQYwCQYHBACORgEGAzB3BgYEAIGYJwIwbTBGMEQGBwQAgZgnAQEMBlBTUF9BUwYH" + - "BACBmCcBAgwGUFNQX1BJBgcEAIGYJwEDDAZQU1BfQUkGBwQAgZgnAQQMBlBTUF9J" + - "QwwbRmluYW5jaWFsIENvbmR1Y3QgQXV0aG9yaXR5DAZHQi1GQ0EwDQYJKoZIhvcN" + - "AQEFBQADggIBABBM63bCwANVRR44wFCZysbppYAT4mms3dUqoP3XCUXaO3+7zNWa" + - "siZ90cje3fuiTD5SAyykm/I/mlgVx92ZbYFW0VG7IVkuC7Fid5iPywHX7Bm1xmEY" + - "bL1AtAm4sBzE1Kw5dnB1L30do7sp9fuJCdom5/fhrh2GyLBd0iA62qQ+F9uALrC0" + - "bub0KnGaEf9g1UltgxuqguoYoHb46ICJ03kMGZMC5BcjDDEbDQQ3kT+g9evaBUBm" + - "3A3cNJURF7/07iLEfHNYrMxDLIw6aC4svbcx+IquO81xpTCefhTU4UFSLN1/DXWW" + - "qrjCqkvHE53mb33QCXmnsooTP8pABG2q2+w5EC9yeX6Fln6M8VwZL5P2stELWXZE" + - "876kCo0LkmoP3s6Z62bF4u9hJvM9mQRvmDVqN2Y7eLMty4qmGEmAYYiHOG+FXNKo" + - "io9MXbB3B7tdeM4g2HlQGfRIrTrfAOu2cH1l1ZwHZgx7oCXN1nuZgE3r07kJx4Bn" + - "DXCRpXoZq4pB3AlzcWEPh51/SS8Wsz52CNSDGoMB7HPkNnoDrYoibb1LFrOwJ3IM" + - "VUKCSnt1QdnrKtMVMTd0iI4uk7kCKt7QFeiizN+oW6BI/MNm6mHEWd9CKWmrZT56" + - "wU3ZM7vgwugq9tAs+oi8Lf3ZODuXAsiSpgcd6dceatoqeyB4E+6kp0Ge" + + "MIIFLTCCBBWgAwIBAgIEWcbiiDANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJH" + + "QjEUMBIGA1UEChMLT3BlbkJhbmtpbmcxLjAsBgNVBAMTJU9wZW5CYW5raW5nIFBy" + + "ZS1Qcm9kdWN0aW9uIElzc3VpbmcgQ0EwHhcNMjMxMTE1MDUxMDA4WhcNMjQxMjE1" + + "MDU0MDA4WjBhMQswCQYDVQQGEwJHQjEUMBIGA1UEChMLT3BlbkJhbmtpbmcxGzAZ" + + "BgNVBAsTEjAwMTU4MDAwMDFIUVFyWkFBWDEfMB0GA1UEAxMWakZRdVE0ZVFiTkNN" + + "U3FkQ29nMjFuRjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKi36HD0" + + "prx1N3pfafJc6pSMg0i0jOiQrt+WZ6GphKUhA2JrbBxWTvabX1Q7hifl5UbkBOkn" + + "n3SCyqBplPSqksYLdPSckb2J7UVLj76O7RkELoFD+vSrQ8FWEn8lXv4UiS8ylvlr" + + "IPa8+pVtAwOuI3/YFmqB1lcHgBI8EELDUWHXSp3OhkcKjrm76t1sQz0tsmi5aHZR" + + "3FXb0dACQO+dGakIerqzUmAdccLtWuSJMT+b7c7IDDm/IR/MV7iol04yeBkOlWre" + + "IKOqHU16PI3N/PSMEt96JAUKZ/n0VC0x4YHaBYDX27sf4Gypubgmkcd4IbG/8XEu" + + "Hq3Ik84oEpP5QEUCAwEAAaOCAfkwggH1MA4GA1UdDwEB/wQEAwIGwDAVBgNVHSUE" + + "DjAMBgorBgEEAYI3CgMMMIHgBgNVHSAEgdgwgdUwgdIGCysGAQQBqHWBBgFkMIHC" + + "MCoGCCsGAQUFBwIBFh5odHRwOi8vb2IudHJ1c3Rpcy5jb20vcG9saWNpZXMwgZMG" + + "CCsGAQUFBwICMIGGDIGDVXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY29uc3RpdHV0" + + "ZXMgYWNjZXB0YW5jZSBvZiB0aGUgT3BlbkJhbmtpbmcgUm9vdCBDQSBDZXJ0aWZp" + + "Y2F0aW9uIFBvbGljaWVzIGFuZCBDZXJ0aWZpY2F0ZSBQcmFjdGljZSBTdGF0ZW1l" + + "bnQwbQYIKwYBBQUHAQEEYTBfMCYGCCsGAQUFBzABhhpodHRwOi8vb2IudHJ1c3Rp" + + "cy5jb20vb2NzcDA1BggrBgEFBQcwAoYpaHR0cDovL29iLnRydXN0aXMuY29tL29i" + + "X3BwX2lzc3VpbmdjYS5jcnQwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL29iLnRy" + + "dXN0aXMuY29tL29iX3BwX2lzc3VpbmdjYS5jcmwwHwYDVR0jBBgwFoAUUHORxiFy" + + "03f0/gASBoFceXluP1AwHQYDVR0OBBYEFKjCef/JxD+ND9eSb7hQlmEhSxUqMA0G" + + "CSqGSIb3DQEBCwUAA4IBAQCnKH9FdLmJMruX2qfbrpT0qaV8bP7xa9UDRYSMsAWC" + + "2kqCxs8CJmARt5+xsxBW6P65+mkLS2vXgQl7J8RTMiQVnHJvvNaldYnV6odsYOqv" + + "v+vGib8Qe0gKWSjih+Gd1Ct4UQFtn6P3ph+6OBB0OieZb7DYXqPJrX5UlG7K2fQ4" + + "0MdFgBdeQZ3iNkXi43UIrQ5cF4cjYavmEFRmYeHya8AKfNCiWly15mNazW/X6SWf" + + "7pz+yk/l+gBv0wm3QT7ANXGf8izgoh6T5fmixPXSbdn8RUIV0kXp2TRRZ+CYUWBP" + + "Jc3PvRXiiEEo2eHLXfEHG2jzrt1iKnjk6hzuC1hUzK0t" + "-----END CERTIFICATE-----"; public static final String EXPIRED_SELF_CERT = "-----BEGIN CERTIFICATE-----" + "MIIDiTCCAnGgAwIBAgIENx3SZjANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJs" + @@ -171,6 +173,14 @@ private static Field getAccessibleField(Class clazz, String fieldName) return field; } + public static synchronized X509Certificate getExpiredSelfCertificate() + throws OpenBankingException { + if (expiredSelfCertificate == null) { + expiredSelfCertificate = CertificateUtils.parseCertificate(EXPIRED_SELF_CERT); + } + return expiredSelfCertificate; + } + private static void injectIntoUnmodifiableMap(String key, String value, Object map) throws ReflectiveOperationException { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/JWTUtilsTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/JWTUtilsTest.java new file mode 100644 index 00000000..0658d00c --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/JWTUtilsTest.java @@ -0,0 +1,72 @@ +/** + * 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 com.wso2.openbanking.accelerator.common.test.util; + +import com.wso2.openbanking.accelerator.common.test.util.testutils.JWTUtilsTestDataProvider; +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.text.ParseException; +import java.util.Date; + +/** + * Test class for Unit Testing JWTUtils. + */ +public class JWTUtilsTest { + + @Test(dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "jwtStrings") + public void testIsJWT(String jwtString, boolean expected) { + + Assert.assertEquals(JWTUtils.isValidJWSFormat(jwtString), expected); + } + + @Test(dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "validParsableJwtStrings") + public void testGetSignedJWT(String jwtString) throws ParseException { + + Assert.assertNotNull(JWTUtils.getSignedJWT(jwtString)); + } + + @Test(expectedExceptions = ParseException.class, + dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "validNotParsableJwtStrings") + public void testGetSignedJWTWIthNotParsableJWT(String jwtString) throws ParseException { + + JWTUtils.getSignedJWT(jwtString); + } + + @Test(expectedExceptions = IllegalArgumentException.class, + dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "notValidJwtStrings") + public void testGetSignedJWTWIthNotValidJWT(String jwtString) throws ParseException { + + JWTUtils.getSignedJWT(jwtString); + } + + @Test(dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "expiryTimeProvider") + public void testValidExpirationTime(Date time, long timeSkew, boolean expected) { + + Assert.assertEquals(JWTUtils.isValidExpiryTime(time, timeSkew), expected); + } + + @Test(dataProviderClass = JWTUtilsTestDataProvider.class, dataProvider = "nbfProvider") + public void testValidNotValidBefore(Date time, long timeSkew, boolean expected) { + + Assert.assertEquals(JWTUtils.isValidNotValidBeforeTime(time, timeSkew), expected); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/OpenBankingUtilsTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/OpenBankingUtilsTest.java index 8e5b76aa..5a408663 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/OpenBankingUtilsTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/OpenBankingUtilsTest.java @@ -19,6 +19,7 @@ package com.wso2.openbanking.accelerator.common.test.util; import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.identity.IdentityConstants; import com.wso2.openbanking.accelerator.common.util.OpenBankingUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -31,6 +32,8 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.text.ParseException; + import static org.mockito.Mockito.when; @@ -55,6 +58,85 @@ public void before() { } + @Test(priority = 1) + public void getSoftwareEnvironmentFromSSA() throws ParseException { + String sandboxSsa = "eyJ0eXAiOiJKV1QiLCJraWQiOiJoM1pDRjBWcnpnWGduSENxYkhiS1h6emZqVGciLCJhbGciOiJQUzI1NiJ9." + + "eyJpYXQiOjE2OTg2ODQ4MjUsIm5iZiI6MTY5ODY4NDgyMSwiZXhwIjoxNjk4Njg4NDI2LCJqdGkiOiIyNDdlNjdmNjBmODA0YT" + + "k5MTY5ODY4NDgyNSIsImlzcyI6Ik9wZW5CYW5raW5nIEx0ZCIsInNvZnR3YXJlX2Vudmlyb25tZW50Ijoic2FuZGJveCIsInNv" + + "ZnR3YXJlX21vZGUiOiJUZXN0Iiwic29mdHdhcmVfaWQiOiIxMlp6RkZCeFNMR0VqUFpvZ1JBYnZGZHMxMTY5ODY4NDgyNSIsIn" + + "NvZnR3YXJlX2NsaWVudF9pZCI6IjEwWnpGRkJ4U0xHRWpQWm9nUkFidkZkczEiLCJzb2Z0d2FyZV9jbGllbnRfbmFtZSI6IldT" + + "TzIgT3BlbiBCYW5raW5nIFRQUCAoU2FuZGJveCkiLCJzb2Z0d2FyZV9jbGllbnRfZGVzY3JpcHRpb24iOiJXU08yIE9wZW4gQm" + + "Fua2luZyBUUFAgZm9yIHRlc3RpbmciLCJzb2Z0d2FyZV92ZXJzaW9uIjoxLjUsInNvZnR3YXJlX2NsaWVudF91cmkiOiJodHRw" + + "czovL3d3dy5nb29nbGUuY29tIiwic29mdHdhcmVfcmVkaXJlY3RfdXJpcyI6WyJodHRwczovL3d3dy5nb29nbGUuY29tL3JlZG" + + "lyZWN0cy9yZWRpcmVjdDEiXSwic29mdHdhcmVfcm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJdLCJvcmdhbmlzYXRpb25f" + + "Y29tcGV0ZW50X2F1dGhvcml0eV9jbGFpbXMiOnsiYXV0aG9yaXR5X2lkIjoiT0JHQlIiLCJyZWdpc3RyYXRpb25faWQiOiJVbm" + + "tub3duMDAxNTgwMDAwMUhRUXJaQUFYIiwic3RhdHVzIjoiQWN0aXZlIiwiYXV0aG9yaXNhdGlvbnMiOlt7Im1lbWJlcl9zdGF0" + + "ZSI6IkdCIiwicm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJdfSx7Im1lbWJlcl9zdGF0ZSI6IklFIiwicm9sZXMiOlsiUE" + + "lTUCIsIkNCUElJIiwiQUlTUCJdfSx7Im1lbWJlcl9zdGF0ZSI6Ik5MIiwicm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJd" + + "fV19LCJzb2Z0d2FyZV9sb2dvX3VyaSI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20iLCJvcmdfc3RhdHVzIjoiQWN0aXZlIiwib3" + + "JnX2lkIjoiMDAxNTgwMDAwMUhRUXJaQUFYIiwib3JnX25hbWUiOiJXU08yIChVSykgTElNSVRFRCIsIm9yZ19jb250YWN0cyI6" + + "W3sibmFtZSI6IlRlY2huaWNhbCIsImVtYWlsIjoic2FjaGluaXNAd3NvMi5jb20iLCJwaG9uZSI6Iis5NDc3NDI3NDM3NCIsIn" + + "R5cGUiOiJUZWNobmljYWwifSx7Im5hbWUiOiJCdXNpbmVzcyIsImVtYWlsIjoic2FjaGluaXNAd3NvMi5jb20iLCJwaG9uZSI6" + + "Iis5NDc3NDI3NDM3NCIsInR5cGUiOiJCdXNpbmVzcyJ9XSwib3JnX2p3a3NfZW5kcG9pbnQiOiJodHRwczovL2tleXN0b3JlLm" + + "9wZW5iYW5raW5ndGVzdC5vcmcudWsvMDAxNTgwMDAwMUhRUXJaQUFYLzAwMTU4MDAwMDFIUVFyWkFBWC5qd2tzIiwib3JnX2p3" + + "a3NfcmV2b2tlZF9lbmRwb2ludCI6Imh0dHBzOi8va2V5c3RvcmUub3BlbmJhbmtpbmd0ZXN0Lm9yZy51ay8wMDE1ODAwMDAxSF" + + "FRclpBQVgvcmV2b2tlZC8wMDE1ODAwMDAxSFFRclpBQVguandrcyIsInNvZnR3YXJlX2p3a3NfZW5kcG9pbnQiOiJodHRwczov" + + "L2tleXN0b3JlLm9wZW5iYW5raW5ndGVzdC5vcmcudWsvMDAxNTgwMDAwMUhRUXJaQUFYLzAwMTU4MDAwMDFIUVFyWkFBWC5qd2" + + "tzIiwic29mdHdhcmVfandrc19yZXZva2VkX2VuZHBvaW50IjoiaHR0cHM6Ly9rZXlzdG9yZS5vcGVuYmFua2luZ3Rlc3Qub3Jn" + + "LnVrLzAwMTU4MDAwMDFIUVFyWkFBWC9yZXZva2VkLzlaekZGQnhTTEdFalBab2dSQWJ2RmQuandrcyIsInNvZnR3YXJlX3BvbG" + + "ljeV91cmkiOiJodHRwczovL3d3dy5nb29nbGUuY29tIiwic29mdHdhcmVfdG9zX3VyaSI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5j" + + "b20iLCJzb2Z0d2FyZV9vbl9iZWhhbGZfb2Zfb3JnIjpudWxsfQ.SUZaSo0sEfBU2ffN73IqNG8KAoYEO8vUIrZHBOxA-gF5dKN" + + "IZR6pQ9cnuc3NzhmfHr9TAhiC_KVV9ULiwg0Kh0V79z57Ykjz6NuZ8m0tZPQbjOMQBrRXdnLkqqot_pO_2vwLCRFDfhWM2wqR4" + + "lTXkM0KsdNSWgG3vl25JTkwqo1tTsYlZUcQFltlLQ-lCXT2nWnu_dPZWUqzVb9g4s2DcQ78xkJwqHJKgGLsloXzAMDx36MZQ01" + + "fHP2eIFu82D0PgsxqvHbNeyXVlg5XsX5TLRwrRy8W4wP_SLMoP7jDic0yEufBRULROX2ckpoZuk31a_QyaJFKtIiPj9zlltM9Zg"; + PowerMockito.when(OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyValueForSandbox()).thenReturn("sandbox"); + PowerMockito.when(OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyName()).thenReturn("software_environment"); + String softwareEnvironmentFromSSA = OpenBankingUtils.getSoftwareEnvironmentFromSSA(sandboxSsa); + Assert.assertEquals(softwareEnvironmentFromSSA, IdentityConstants.SANDBOX); + } + + @Test() + public void getSoftwareEnvironmentFromSSAForProd() throws ParseException { + String prodSsa = "eyJ0eXAiOiJKV1QiLCJraWQiOiJoM1pDRjBWcnpnWGduSENxYkhiS1h6emZqVGciLCJhbGciOiJQUzI1NiJ9." + + "eyJpYXQiOjE2OTg2ODQ4MjUsIm5iZiI6MTY5ODY4NDgyMSwiZXhwIjoxNjk4Njg4NDI2LCJqdGkiOiIyNDdlNjdmNjBmODA0YT" + + "k5MTY5ODY4NDgyNSIsImlzcyI6Ik9wZW5CYW5raW5nIEx0ZCIsInNvZnR3YXJlX2Vudmlyb25tZW50IjoicHJvZCIsInNvZnR3" + + "YXJlX21vZGUiOiJUZXN0Iiwic29mdHdhcmVfaWQiOiIxMlp6RkZCeFNMR0VqUFpvZ1JBYnZGZHMxMTY5ODY4NDgyNSIsInNvZn" + + "R3YXJlX2NsaWVudF9pZCI6IjEwWnpGRkJ4U0xHRWpQWm9nUkFidkZkczEiLCJzb2Z0d2FyZV9jbGllbnRfbmFtZSI6IldTTzIg" + + "T3BlbiBCYW5raW5nIFRQUCAoU2FuZGJveCkiLCJzb2Z0d2FyZV9jbGllbnRfZGVzY3JpcHRpb24iOiJXU08yIE9wZW4gQmFua2" + + "luZyBUUFAgZm9yIHRlc3RpbmciLCJzb2Z0d2FyZV92ZXJzaW9uIjoxLjUsInNvZnR3YXJlX2NsaWVudF91cmkiOiJodHRwczov" + + "L3d3dy5nb29nbGUuY29tIiwic29mdHdhcmVfcmVkaXJlY3RfdXJpcyI6WyJodHRwczovL3d3dy5nb29nbGUuY29tL3JlZGlyZW" + + "N0cy9yZWRpcmVjdDEiXSwic29mdHdhcmVfcm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJdLCJvcmdhbmlzYXRpb25fY29t" + + "cGV0ZW50X2F1dGhvcml0eV9jbGFpbXMiOnsiYXV0aG9yaXR5X2lkIjoiT0JHQlIiLCJyZWdpc3RyYXRpb25faWQiOiJVbmtub3" + + "duMDAxNTgwMDAwMUhRUXJaQUFYIiwic3RhdHVzIjoiQWN0aXZlIiwiYXV0aG9yaXNhdGlvbnMiOlt7Im1lbWJlcl9zdGF0ZSI6" + + "IkdCIiwicm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJdfSx7Im1lbWJlcl9zdGF0ZSI6IklFIiwicm9sZXMiOlsiUElTUC" + + "IsIkNCUElJIiwiQUlTUCJdfSx7Im1lbWJlcl9zdGF0ZSI6Ik5MIiwicm9sZXMiOlsiUElTUCIsIkFJU1AiLCJDQlBJSSJdfV19" + + "LCJzb2Z0d2FyZV9sb2dvX3VyaSI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20iLCJvcmdfc3RhdHVzIjoiQWN0aXZlIiwib3JnX2" + + "lkIjoiMDAxNTgwMDAwMUhRUXJaQUFYIiwib3JnX25hbWUiOiJXU08yIChVSykgTElNSVRFRCIsIm9yZ19jb250YWN0cyI6W3si" + + "bmFtZSI6IlRlY2huaWNhbCIsImVtYWlsIjoic2FjaGluaXNAd3NvMi5jb20iLCJwaG9uZSI6Iis5NDc3NDI3NDM3NCIsInR5cG" + + "UiOiJUZWNobmljYWwifSx7Im5hbWUiOiJCdXNpbmVzcyIsImVtYWlsIjoic2FjaGluaXNAd3NvMi5jb20iLCJwaG9uZSI6Iis5" + + "NDc3NDI3NDM3NCIsInR5cGUiOiJCdXNpbmVzcyJ9XSwib3JnX2p3a3NfZW5kcG9pbnQiOiJodHRwczovL2tleXN0b3JlLm9wZW" + + "5iYW5raW5ndGVzdC5vcmcudWsvMDAxNTgwMDAwMUhRUXJaQUFYLzAwMTU4MDAwMDFIUVFyWkFBWC5qd2tzIiwib3JnX2p3a3Nf" + + "cmV2b2tlZF9lbmRwb2ludCI6Imh0dHBzOi8va2V5c3RvcmUub3BlbmJhbmtpbmd0ZXN0Lm9yZy51ay8wMDE1ODAwMDAxSFFRcl" + + "pBQVgvcmV2b2tlZC8wMDE1ODAwMDAxSFFRclpBQVguandrcyIsInNvZnR3YXJlX2p3a3NfZW5kcG9pbnQiOiJodHRwczovL2tl" + + "eXN0b3JlLm9wZW5iYW5raW5ndGVzdC5vcmcudWsvMDAxNTgwMDAwMUhRUXJaQUFYLzAwMTU4MDAwMDFIUVFyWkFBWC5qd2tzIi" + + "wic29mdHdhcmVfandrc19yZXZva2VkX2VuZHBvaW50IjoiaHR0cHM6Ly9rZXlzdG9yZS5vcGVuYmFua2luZ3Rlc3Qub3JnLnVr" + + "LzAwMTU4MDAwMDFIUVFyWkFBWC9yZXZva2VkLzlaekZGQnhTTEdFalBab2dSQWJ2RmQuandrcyIsInNvZnR3YXJlX3BvbGljeV" + + "91cmkiOiJodHRwczovL3d3dy5nb29nbGUuY29tIiwic29mdHdhcmVfdG9zX3VyaSI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20i" + + "LCJzb2Z0d2FyZV9vbl9iZWhhbGZfb2Zfb3JnIjpudWxsfQ.NLglx-H9D-i2f9GmSrxq00wTlKGHW_6zmKxGg_UhX0P0dzqJmNW" + + "UCDBdz-HhjlPSGeLqumyM_hJZELGv96p6CllmHdNA12gIGem3oBqnaPq9wfcr5Esn7sfRODPComjr6lKxNSXraLT7qpRHCJoxq" + + "yi72RH7T6HyF5lobTHWcZRkCNtc9cWJMKbftGCDSGRlO0XSYvvdGMDBCQT5-KiuKiWcKcBcFX2TLpTDDYaf-GNtATQ0O_vl266" + + "fDPyzG9XF6NLheG0ITrTBGuVN2JzSDC50_vCqR754LtFKNLXKQ2WTnrY3TgEBbyaKj3N0_YdDIuT442zkadg8lvoNpXyk4A"; + + PowerMockito.when(OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyValueForSandbox()).thenReturn("sandbox"); + PowerMockito.when(OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyName()).thenReturn("software_environment"); + String softwareEnvironmentFromSSA = OpenBankingUtils.getSoftwareEnvironmentFromSSA(prodSsa); + Assert.assertEquals(softwareEnvironmentFromSSA, IdentityConstants.PRODUCTION); + } + @Test public void testDisputeDataWhenNonErrorPublishingEnabled() throws Exception { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/SecurityUtilsTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/SecurityUtilsTest.java new file mode 100644 index 00000000..2e9437f0 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/SecurityUtilsTest.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 com.wso2.openbanking.accelerator.common.test.util; + +import com.wso2.openbanking.accelerator.common.util.SecurityUtils; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Tests Common Security Utils. + */ +public class SecurityUtilsTest { + + @Test + public void testSanitizeString() { + String sanitizedString = SecurityUtils.sanitizeString("tests\nsanitizing"); + Assert.assertFalse(sanitizedString.contains("\n")); + } + + @Test + public void testSanitizeStringList() { + List sanitizedList = new ArrayList<>(); + sanitizedList.add("tests\nsanitizing"); + sanitizedList.add("tests\nsan\nitizing"); + sanitizedList.add("tests\nsanitizing\n"); + + Assert.assertFalse(SecurityUtils.sanitize(sanitizedList).stream().anyMatch(s -> s.contains("\n"))); + } + + @Test + public void testSanitizeStringSet() { + Set sanitizedList = new HashSet<>(); + sanitizedList.add("tests\nsanitizing"); + sanitizedList.add("tests\nsanitizingtext"); + sanitizedList.add("tests\nsanitizingwords"); + + Assert.assertFalse(SecurityUtils.sanitize(sanitizedList).stream().anyMatch(s -> s.contains("\n"))); + } + + @Test + public void testContainSpecialChars() { + Assert.assertTrue(SecurityUtils.containSpecialChars("tests&sanitizing")); + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/testutils/JWTUtilsTestDataProvider.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/testutils/JWTUtilsTestDataProvider.java new file mode 100644 index 00000000..c1ef208f --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/util/testutils/JWTUtilsTestDataProvider.java @@ -0,0 +1,132 @@ +/** + * 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 com.wso2.openbanking.accelerator.common.test.util.testutils; + +import org.testng.annotations.DataProvider; + +import java.util.Date; + +/** + * Data Provider for JWTUtilsTest. + */ +public class JWTUtilsTestDataProvider { + + @DataProvider(name = "jwtStrings") + + public Object[][] getJwtStrings() { + + return new Object[][] { + + // Valid JWT String + {"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpv" + + "aG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflK.xwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + true}, + // Empty String + {"", false}, + // Null String + {null, false}, + // Invalid JWT String with less than 2 dots + {"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", false}, + // Invalid JWT String with more than 2 dots + {"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4" + + "gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.extra", + false}, + // JWT String with whitespace + {" eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG" + + "4gRG9lIiwiaWF0IjoxNT.E2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ", + true}, + // JWT String with only dots + {"...", false}, + // JWT String with valid segments but invalid encoding + {"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.InvalidBase64.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + true}, + // JWT String with valid segments and valid encoding but invalid JSON + {"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG" + + "9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.invalidJSON", + true} + }; + } + + @DataProvider(name = "validParsableJwtStrings") + public Object[][] getValidParsablejwtStrings() { + + String parsableJwtString = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ3LT" + + "RlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb2dpbkhpbnQiOiJhZG1pbkB3c28yLmNvb" + + "SIsImlhdCI6MTcxNDkyOTk2MCwianRpIjoiNmU0MWM4N2UtYWJmNi00ZjU1LTliNjQt" + + "NjYwMWFlODg2NjZjIiwiZXhwIjoxNzE0OTMxNzYwLCJuYmYiOjE3MTQ5Mjk5NjB9.WB" + + "7qvq3w6htUop600H5C4HwL-r0wb8GekJE6X4-zrFn2IofEcwV0yisSE5fH8uyrzdmVm" + + "OiBgFXY9Y9cUVlS6t9HMbhlzs2qY0bVzDYVNG7GjgnYIcyh3lx9obqL9O3DJKNre5GS" + + "3b-ATPN6VvYC9F2KnwwuoNky-3Wlcw3G9-E"; + + return new String[][] { + {parsableJwtString} + }; + } + + @DataProvider(name = "validNotParsableJwtStrings") + public Object[][] getValidNotParsableJwtStrings() { + + String notParsableJwtString = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXNOTVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ" + + "RlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb2dpbkhpbnQiOiJhZG1pbkB3c28yLmNvb" + + "SIsImlhdCI6MTcxNDkyOTk2MCwianRpIjoiNmU0MWM4N2UtYWJmNi00ZjU1LTliNjQt" + + "NjYwMWFlODg2NjZjIiwiZXhwIjoxNzE0OTMxNzYwLCJuYmYiOjE3MTQ5Mjk5NjB9.WB" + + "7qvq3w6htUop600H5C4HwL-r0wb8GekJE6X4-zrFn2IofEcwV0yisSE5fH8uyrzdmVm" + + "OiBgFXY9Y9cUVlS6t9HMbhlzs2qY0bVzDYVNG7GjgnYIcyh3lx9obqL9O3DJKNre5GS" + + "3b-ATPN6VvYC9F2KnwwuoNky-3Wlcw3G9-E3LT"; + + return new String[][] { + {notParsableJwtString} + }; + } + + @DataProvider(name = "notValidJwtStrings") + public Object[][] getNotValidJwtStrings() { + + String notValidJwtString = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4" + + "gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.extra"; + + return new String[][] { + {notValidJwtString} + }; + } + + @DataProvider(name = "expiryTimeProvider") + public Object[][] getExpiryTime() { + + return new Object[][]{ + {null, 0, false}, + {new Date(System.currentTimeMillis() - 10 * 1000), 0, false}, + {new Date(System.currentTimeMillis() + 10 * 100), 0, true} + }; + } + + @DataProvider(name = "nbfProvider") + public Object[][] getNbf() { + + return new Object[][]{ + {null, 0, false}, + {new Date(System.currentTimeMillis() + 10 * 1000), 0, false}, + {new Date(System.currentTimeMillis() - 3 * 1000), 0, true} + }; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/open-banking.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/open-banking.xml index 248c38a6..a3dbb816 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/open-banking.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/open-banking.xml @@ -156,6 +156,9 @@ + + true + @@ -207,7 +210,7 @@ - + com.wso2.openbanking.accelerator.keymanager.OBKeyManagerImpl diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/testng.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/testng.xml index b791b6f8..9b956e1e 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/testng.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/resources/testng.xml @@ -50,19 +50,19 @@ - + - + - + - + - + - + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.authentication.data.publisher/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.authentication.data.publisher/pom.xml index 076a0d06..cd79cfd7 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.authentication.data.publisher/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.authentication.data.publisher/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 com.wso2.openbanking.accelerator.data.publisher - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../pom.xml @@ -47,11 +45,11 @@ org.wso2.carbon.identity.application.authentication.framework - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.data.publisher.common - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/pom.xml index 00443cc8..281e547a 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -37,7 +35,7 @@ org.wso2.carbon.databridge.agent - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common @@ -50,6 +48,16 @@ testng test + + org.powermock + powermock-module-testng + test + + + org.powermock + powermock-api-mockito + test + org.mockito mockito-all diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/constants/DataPublishingConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/constants/DataPublishingConstants.java index dcccccf7..30f8d7e1 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/constants/DataPublishingConstants.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/constants/DataPublishingConstants.java @@ -31,10 +31,11 @@ public class DataPublishingConstants { public static final String DATA_PUBLISHING_POOL_WAIT_TIME = "DataPublishing.PoolWaitTimeMs"; public static final String DATA_PUBLISHING_PROTOCOL = "DataPublishing.Protocol"; public static final String DATA_PUBLISHING_ENABLED = "DataPublishing.Enabled"; + public static final String ELK_ANALYTICS_ENABLED = "ELKAnalytics.Enabled"; public static final String APIM_ANALYTICS_ENABLED = "APIMAnalytics.Enabled"; public static final String QUEUE_SIZE = "DataPublishing.QueueSize"; public static final String WORKER_THREAD_COUNT = "DataPublishing.WorkerThreadCount"; - public static final String THRIFT_PUBLISHING_TIMEOUT = "DataPublishing.Thrift.PublishingTimeout"; + public static final String LOG_FILE_NAME = "OB_LOG"; } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/util/OBDataPublisherUtil.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/util/OBDataPublisherUtil.java index 9a9b1414..771b8d4d 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/util/OBDataPublisherUtil.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/main/java/com/wso2/openbanking/accelerator/data/publisher/common/util/OBDataPublisherUtil.java @@ -18,6 +18,9 @@ package com.wso2.openbanking.accelerator.data.publisher.common.util; +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.AnalyticsLogsUtils; import com.wso2.openbanking.accelerator.data.publisher.common.DataPublisherPool; import com.wso2.openbanking.accelerator.data.publisher.common.EventQueue; import com.wso2.openbanking.accelerator.data.publisher.common.OpenBankingDataPublisher; @@ -60,6 +63,17 @@ public static void releaseDataPublishingInstance(OpenBankingDataPublisher instan */ public static void publishData(String streamName, String streamVersion, Map analyticsData) { + // Analytics data will be added to the OB analytics logfile for processing if ELK is configured for the server. + if (Boolean.parseBoolean((String) OpenBankingConfigParser.getInstance().getConfiguration() + .get(DataPublishingConstants.ELK_ANALYTICS_ENABLED))) { + try { + AnalyticsLogsUtils.addAnalyticsLogs(DataPublishingConstants.LOG_FILE_NAME, streamName, + streamVersion, analyticsData); + } catch (OpenBankingException e) { + log.error("Error occurred while writing analytics logs", e); + } + } + if (Boolean.parseBoolean((String) OBAnalyticsDataHolder.getInstance().getConfigurationMap() .get(DataPublishingConstants.DATA_PUBLISHING_ENABLED))) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/test/java/com/wso2/openbanking/accelerator/data/publisher/common/OBAnalyticsEventQueueTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/test/java/com/wso2/openbanking/accelerator/data/publisher/common/OBAnalyticsEventQueueTest.java index 7c58ed41..522ca4ef 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/test/java/com/wso2/openbanking/accelerator/data/publisher/common/OBAnalyticsEventQueueTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/com.wso2.openbanking.accelerator.data.publisher.common/src/test/java/com/wso2/openbanking/accelerator/data/publisher/common/OBAnalyticsEventQueueTest.java @@ -18,12 +18,22 @@ package com.wso2.openbanking.accelerator.data.publisher.common; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigurationService; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingRuntimeException; import com.wso2.openbanking.accelerator.data.publisher.common.internal.OBAnalyticsDataHolder; import com.wso2.openbanking.accelerator.data.publisher.common.util.OBDataPublisherUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -36,7 +46,12 @@ /** * Open Banking analytics event queue test. */ -public class OBAnalyticsEventQueueTest { +@PowerMockIgnore({"jdk.internal.reflect.*"}) +@PrepareForTest({OpenBankingConfigParser.class}) +public class OBAnalyticsEventQueueTest extends PowerMockTestCase { + + @Mock + OpenBankingConfigParser openBankingConfigParser; private static ByteArrayOutputStream outContent; private static Logger logger = null; @@ -45,6 +60,7 @@ public class OBAnalyticsEventQueueTest { @BeforeClass public void beforeTests() { + MockitoAnnotations.initMocks(this); outContent = new ByteArrayOutputStream(); printStream = new PrintStream(outContent); System.setOut(printStream); @@ -59,6 +75,12 @@ public void testAddingDataToQueue() { configs.put("DataPublishing.WorkerThreadCount", "3"); configs.put("DataPublishing.QueueSize", "10"); configs.put("DataPublishing.Enabled", "true"); + configs.put("ELKAnalytics.Enabled", "true"); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + Mockito.when(OpenBankingConfigParser.getInstance()) + .thenReturn(openBankingConfigParser); + Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configs); OpenBankingConfigurationService openBankingConfigurationService = Mockito.mock(OpenBankingConfigurationService.class); @@ -67,7 +89,14 @@ public void testAddingDataToQueue() { OBAnalyticsDataHolder.getInstance().setOpenBankingConfigurationService(openBankingConfigurationService); OBDataPublisherUtil.publishData("testStream", "1.0", configs); - Assert.assertTrue(outContent.toString().isEmpty()); + try { + Assert.assertTrue(outContent.toString().contains("Data Stream : testStream , Data Stream Version : 1.0 , " + + "Data : {\"payload\":" + new ObjectMapper().writeValueAsString(configs) + "}")); + Assert.assertFalse(outContent.toString().contains("Data publishing is disabled. " + + "Failed to obtain a data publisher instance.")); + } catch (JsonProcessingException e) { + throw new OpenBankingRuntimeException("Error in processing JSON payload", e); + } } @Test @@ -78,6 +107,12 @@ public void tryAddingToQueueWhenDataPublishingDisabled() { configs.put("DataPublishing.WorkerThreadCount", "3"); configs.put("DataPublishing.QueueSize", "10"); configs.put("DataPublishing.Enabled", "false"); + configs.put("ELKAnalytics.Enabled", "true"); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + Mockito.when(OpenBankingConfigParser.getInstance()) + .thenReturn(openBankingConfigParser); + Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configs); OpenBankingConfigurationService openBankingConfigurationService = Mockito.mock(OpenBankingConfigurationService.class); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/pom.xml index d985fa21..ec348abf 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.data.publisher/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/pom.xml index 126980e1..c3456744 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml @@ -46,7 +44,7 @@ commons-logging - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common @@ -62,7 +60,7 @@ swagger-parser - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.data.publisher.common @@ -72,8 +70,8 @@ - org.bouncycastle - bcprov-jdk15on + org.wso2.orbit.org.bouncycastle + bcprov-jdk18on org.testng @@ -147,11 +145,6 @@ - - com.hazelcast - hazelcast - test - org.wso2.orbit.com.nimbusds nimbus-jose-jwt diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyCacheKey.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyCacheKey.java deleted file mode 100644 index 6d9dd690..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyCacheKey.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.gateway.cache; - -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheKey; - -/** - * Cache Key for Open Banking Idempotency cache. - */ -public class OpenBankingIdempotencyCacheKey extends OpenBankingDistributedCacheKey { - - private static final long serialVersionUID = -6635236272993690731L; - - /** - * public constructor for OpenBankingDistributedCacheKey. - * - * @param cacheKey String cache key. - */ - public OpenBankingIdempotencyCacheKey(String cacheKey) { - super(cacheKey); - } - - /** - * Static method to create a cache key. - * - * @param cacheKey cache key in string. - * @return OpenBankingIdempotencyCacheKey. - */ - public static OpenBankingIdempotencyCacheKey of(String cacheKey) { - return new OpenBankingIdempotencyCacheKey(cacheKey); - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyValidationCache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyValidationCache.java deleted file mode 100644 index 1a683c22..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/cache/OpenBankingIdempotencyValidationCache.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.gateway.cache; - -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCache; -import com.wso2.openbanking.accelerator.gateway.util.IdempotencyConstants; - -import java.util.HashMap; - -/** - * Cache definition to store Request against the idempotency key. - */ -public class OpenBankingIdempotencyValidationCache - extends OpenBankingDistributedCache> { - - private final int cacheTimeToLiveMinutes; - private static final String cacheName = "Idempotency-Validation-Cache"; - private static volatile OpenBankingIdempotencyValidationCache idempotencyValidationCache; - - /** - * Initialize With unique cache name. - * - * @param cacheName Name of the cache. - */ - private OpenBankingIdempotencyValidationCache(String cacheName) { - super(cacheName); - this.cacheTimeToLiveMinutes = setCacheTimeToLiveMinutes(); - } - - /** - * Creating a singleton OpenBankingIdempotencyValidationCache object. - * - * @return OpenBankingIdempotencyValidationCache object. - */ - public static OpenBankingIdempotencyValidationCache getInstance() { - if (idempotencyValidationCache == null) { - synchronized (OpenBankingIdempotencyValidationCache.class) { - if (idempotencyValidationCache == null) { - idempotencyValidationCache = new OpenBankingIdempotencyValidationCache( - OpenBankingIdempotencyValidationCache.cacheName); - } - } - } - return idempotencyValidationCache; - } - - /** - * Getter for cache time to live in minutes. - * - * @return cache time to live for Open Banking Idempotency Validation Cache. - */ - @Override - public int getCacheTimeToLiveMinutes() { - return this.cacheTimeToLiveMinutes; - } - - /** - * Method to read cache time to live from configurations. - * - * @return Open Banking Idempotency Validation Cache time to live in minutes as set configurations, - * if configuration is not set return 3600 as default. - */ - public int setCacheTimeToLiveMinutes() { - String cacheTimeToLive = (String) OpenBankingConfigParser.getInstance().getConfiguration() - .get(IdempotencyConstants.IDEMPOTENCY_CACHE_TIME_TO_LIVE); - - return cacheTimeToLive == null ? 3600 : Integer.parseInt(cacheTimeToLive); - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutor.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutor.java index a86cedbd..3eefec9c 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutor.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutor.java @@ -15,6 +15,7 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.gateway.executor.dcr; import com.google.gson.JsonArray; @@ -27,10 +28,10 @@ import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; import com.wso2.openbanking.accelerator.common.error.OpenBankingErrorCodes; import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; -import com.wso2.openbanking.accelerator.common.identity.IdentityConstants; import com.wso2.openbanking.accelerator.common.util.Generated; import com.wso2.openbanking.accelerator.common.util.HTTPClientUtils; import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.common.util.OpenBankingUtils; import com.wso2.openbanking.accelerator.gateway.cache.GatewayCacheKey; import com.wso2.openbanking.accelerator.gateway.executor.core.OpenBankingGatewayExecutor; import com.wso2.openbanking.accelerator.gateway.executor.exception.OpenBankingExecutorException; @@ -72,9 +73,11 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.ws.rs.HttpMethod; @@ -128,7 +131,10 @@ public void preProcessRequest(OBAPIRequestContext obapiRequestContext) { } catch (ParseException e) { log.error("Error occurred while decoding the provided jwt", e); handleBadRequestError(obapiRequestContext, "Malformed request JWT"); - } catch (JOSEException | BadJOSEException | MalformedURLException e) { + } catch (BadJOSEException e) { + log.error("Error occurred while validating the signature", e); + handleBadRequestError(obapiRequestContext, "Invalid request signature. " + e.getMessage()); + } catch (JOSEException | MalformedURLException e) { log.error("Error occurred while validating the signature", e); handleBadRequestError(obapiRequestContext, "Invalid request signature"); } catch (OpenBankingExecutorException e) { @@ -147,390 +153,28 @@ public void postProcessResponse(OBAPIResponseContext obapiResponseContext) { } String basicAuthHeader = GatewayUtils.getBasicAuthHeader(urlMap.get(userName).toString(), String.valueOf((char[]) urlMap.get(GatewayConstants.PASSWORD))); - String fullBackEndURL = urlMap.get(GatewayConstants.IAM_HOSTNAME).toString().concat("/") - .concat(obDCREndpoint); Map> regulatoryAPIs = GatewayDataHolder.getInstance() .getOpenBankingConfigurationService().getAllowedAPIs(); - if (HttpMethod.POST.equalsIgnoreCase(obapiResponseContext.getMsgInfo().getHttpMethod()) - && HttpStatus.SC_CREATED == obapiResponseContext.getStatusCode()) { - try { - JsonParser jsonParser = new JsonParser(); - JsonObject createdDCRAppDetails = ((JsonObject) jsonParser - .parse(obapiResponseContext.getResponsePayload())); - String softwareStatement = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT) - .getAsString(); - //call IS DCR endpoint to create application for obtaining a token to invoke devportal REST APIs - JsonElement registrationResponse = createServiceProvider(basicAuthHeader, - createdDCRAppDetails.get("software_id").getAsString()); - if (registrationResponse == null) { - log.error("Error while creating AM app for invoking APIM rest apis"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - //call token endpoint to retrieve a token for invoking the devportal REST apis - String amRestAPIInvokeClientId = registrationResponse.getAsJsonObject() - .get(clientIdParam).getAsString(); - - String authHeaderForTokenRequest = GatewayUtils - .getBasicAuthHeader(registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(), - registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); - - JsonElement tokenResponse = getToken(authHeaderForTokenRequest, - urlMap.get(GatewayConstants.TOKEN_URL).toString(), amRestAPIInvokeClientId); - - if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { - log.error("Error while creating tokens"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); - String getSPDetails = urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(createdDCRAppDetails.get(clientIdParam).getAsString()); - //call IS dcr api to get client secret and client name - JsonElement createdSpDetails = callGet(getSPDetails, basicAuthHeader, "", ""); - if (createdSpDetails == null) { - log.error("Error while retrieving client id and secret"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - - //create am application - JsonObject amAppCreatePayload = getAppCreatePayload(createdSpDetails.getAsJsonObject() - .get("client_name").getAsString()); - JsonElement amApplicationCreateResponse = - callPost(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), - amAppCreatePayload.toString(), GatewayConstants.BEARER_TAG.concat(token)); - - if (amApplicationCreateResponse == null) { - log.error("Error while creating AM app"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - String keyMapURL = urlMap.get(GatewayConstants.KEY_MAP_URL).toString() - .replace("application-id", amApplicationCreateResponse.getAsJsonObject() - .get(applicationIdParam).getAsString()); - String keyManagerName = GatewayDataHolder.getInstance().getOpenBankingConfigurationService() - .getConfigurations().get(OpenBankingConstants.OB_KM_NAME).toString(); - - //map keys to am application - JsonObject keyMapPayload = getKeyMapPayload(createdDCRAppDetails.get(clientIdParam).getAsString(), - createdSpDetails.getAsJsonObject().get(clientSecret).getAsString(), - getSoftwareEnvironmentFromSSA(softwareStatement), keyManagerName); - - JsonElement amKeyMapResponse = callPost(keyMapURL, keyMapPayload.toString(), - GatewayConstants.BEARER_TAG.concat(token)); - if (amKeyMapResponse == null) { - log.error("Error while mapping keys to AM app"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - //delete AM application - callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() - .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() - .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - //get list of published APIs - JsonElement publishedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_RETRIEVE_URL).toString(), - GatewayConstants.BEARER_TAG.concat(token), "", ""); - if (publishedAPIsResponse == null) { - log.error("Error while retrieving published APIs"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - //delete AM application - callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() - .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() - .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - List apiIDList = new ArrayList<>(); - if (regulatoryAPIs != null) { - apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() - .get("list").getAsJsonArray(), getRolesFromSSA(softwareStatement)); - } else { - log.warn("No regulatory APIs configured. Application will be subscribed to all published APIs"); - //subscribe to all APIs if there are no configured regulatory APIs - for (JsonElement apiInfo : publishedAPIsResponse.getAsJsonObject().get("list").getAsJsonArray()) { - apiIDList.add(apiInfo.getAsJsonObject().get("id").getAsString()); - } + switch (obapiResponseContext.getMsgInfo().getHttpMethod().toUpperCase()) { + case HttpMethod.POST : + if (HttpStatus.SC_CREATED == obapiResponseContext.getStatusCode()) { + String fullBackEndURL = urlMap.get(GatewayConstants.IAM_HOSTNAME).toString().concat("/") + .concat(obDCREndpoint); + postProcessResponseForRegister(obapiResponseContext, basicAuthHeader, fullBackEndURL, + regulatoryAPIs); } - //subscribe to apis - JsonArray subscribeAPIsPayload = getAPISubscriptionPayload(amApplicationCreateResponse - .getAsJsonObject().get(applicationIdParam).getAsString(), apiIDList); - JsonElement subscribeAPIsResponse = callPost(urlMap.get(GatewayConstants.API_SUBSCRIBE_URL).toString(), - subscribeAPIsPayload.toString(), "Bearer ".concat(token)); - if (subscribeAPIsResponse == null) { - log.error("Error while subscribing to APIs"); - String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); - //delete service provider - callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); - //delete SP created for calling dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader); - //delete AM application - callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() - .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() - .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; + break; + case HttpMethod.PUT : + if (HttpStatus.SC_OK == obapiResponseContext.getStatusCode()) { + postProcessResponseForUpdate(obapiResponseContext, basicAuthHeader, regulatoryAPIs); } - - //delete IAM application used to invoke am rest endpoints - if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(amRestAPIInvokeClientId), basicAuthHeader)) { - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - return; + break; + case HttpMethod.DELETE : + if (HttpStatus.SC_NO_CONTENT == obapiResponseContext.getStatusCode()) { + postProcessResponseForDelete(obapiResponseContext, basicAuthHeader); } - - } catch (IOException | OpenBankingException | URISyntaxException | ParseException e) { - log.error("Error occurred while creating application", e); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } } - if (HttpMethod.PUT.equalsIgnoreCase(obapiResponseContext.getMsgInfo().getHttpMethod()) - && HttpStatus.SC_OK == obapiResponseContext.getStatusCode()) { - - JsonParser jsonParser = new JsonParser(); - JsonObject createdDCRAppDetails = ((JsonObject) jsonParser.parse(obapiResponseContext - .getResponsePayload())); - try { - JsonObject dcrPayload = getIAMDCRPayload(createdDCRAppDetails.get("software_id").getAsString()); - JsonElement registrationResponse = callPost(urlMap.get(GatewayConstants.IAM_DCR_URL).toString(), - dcrPayload.toString(), basicAuthHeader); - if (registrationResponse == null) { - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - - //call token endpoint to retrieve a token for invoking the devportal REST apis - String clientId = registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(); - String authHeaderForTokenRequest = GatewayUtils.getBasicAuthHeader(clientId, - registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); - - JsonElement tokenResponse = getToken(authHeaderForTokenRequest, - urlMap.get(GatewayConstants.TOKEN_URL).toString(), clientId); - if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { - log.error("Error while creating tokens"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); - - String applicationName = getApplicationName(obapiResponseContext.getResponsePayload(), - GatewayDataHolder.getInstance().getOpenBankingConfigurationService().getConfigurations()); - if (StringUtils.isEmpty(applicationName)) { - log.error("Error while retrieving application name during update"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - //call application get endpoint to retrieve the application id - JsonElement applicationSearchResponse = - callGet(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), - GatewayConstants.BEARER_TAG.concat(token), "query", applicationName); - if (applicationSearchResponse == null) { - log.error("Error while searching for created application during update"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - String applicationId = applicationSearchResponse.getAsJsonObject().get("list").getAsJsonArray().get(0) - .getAsJsonObject().get(applicationIdParam).getAsString(); - - //get list of subscribed APIs - JsonElement subscribedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString(), - GatewayConstants.BEARER_TAG.concat(token), "applicationId", applicationId); - if (subscribedAPIsResponse == null) { - log.error("Error while retrieving subscribed APIs"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - List allowedRoles = getRolesFromSSA(createdDCRAppDetails - .get(OpenBankingConstants.SOFTWARE_STATEMENT).getAsString()); - List subscribedAPIIdList = new ArrayList<>(); - for (JsonElement subscribedAPI : subscribedAPIsResponse.getAsJsonObject().get("list") - .getAsJsonArray()) { - String apiId = subscribedAPI.getAsJsonObject().get("apiId").getAsString(); - subscribedAPIIdList.add(apiId); - } - //check whether the ssa still contains the roles related to the subscribed APIs - List unsubscribedAPIs = getUnAuthorizedAPIs(subscribedAPIsResponse.getAsJsonObject() - .get("list").getAsJsonArray(), regulatoryAPIs, allowedRoles); - if (!unsubscribedAPIs.isEmpty()) { - //unsubscribe from the apis - for (String subscriptionId : unsubscribedAPIs) { - if (!callDelete(urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString() - .concat("/").concat(subscriptionId), GatewayConstants.BEARER_TAG.concat(token))) { - log.error("Error while unsubscribing from APIs"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, - OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); - return; - } - } - } - //subscribe to new APIs if new roles were added to the SSA - //get list of published APIs - JsonElement publishedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_RETRIEVE_URL).toString(), - GatewayConstants.BEARER_TAG.concat(token), "", ""); - if (publishedAPIsResponse == null) { - log.error("Error while retrieving published APIs"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - List apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() - .get("list").getAsJsonArray(), allowedRoles); - List newApisListToSubscribe = getNewAPIsToSubscribe(apiIDList, subscribedAPIIdList); - if (!newApisListToSubscribe.isEmpty()) { - JsonArray subscribeAPIsPayload = getAPISubscriptionPayload(applicationId, newApisListToSubscribe); - JsonElement subscribeAPIsResponse = callPost(urlMap.get(GatewayConstants.API_SUBSCRIBE_URL) - .toString(), subscribeAPIsPayload.toString(), "Bearer ".concat(token)); - if (subscribeAPIsResponse == null) { - log.error("Error while subscribing to APIs"); - //delete SP created to call dev portal REST APIs - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader); - handleInternalServerError(obapiResponseContext, - OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - } - //delete IAM application used to invoke am rest endpoints - if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") - .concat(clientId), basicAuthHeader)) { - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - } catch (ParseException | IOException | URISyntaxException | OpenBankingException e) { - log.error("Error occurred while creating application", e); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); - return; - } - } - - if (HttpMethod.DELETE.equalsIgnoreCase(obapiResponseContext.getMsgInfo().getHttpMethod()) && - HttpStatus.SC_NO_CONTENT == obapiResponseContext.getStatusCode()) { - try { - JsonObject dcrPayload = getIAMDCRPayload(obapiResponseContext.getApiRequestInfo().getConsumerKey()); - JsonElement registrationResponse = callPost(urlMap.get(GatewayConstants.IAM_DCR_URL).toString(), - dcrPayload.toString(), basicAuthHeader); - if (registrationResponse == null) { - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - return; - } - - //call token endpoint to retrieve a token for invoking the devportal REST apis - String clientId = registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(); - String authHeaderForTokenRequest = GatewayUtils.getBasicAuthHeader(clientId, - registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); - - JsonElement tokenResponse = getToken(authHeaderForTokenRequest, - urlMap.get(GatewayConstants.TOKEN_URL).toString(), clientId); - if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { - log.error("Error while creating tokens during delete"); - //delete IAM application used to invoke am rest endpoints - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), - basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - return; - } - String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); - - //get application id of the sent request - String cacheKey = obapiResponseContext.getApiRequestInfo().getConsumerKey() - .concat(GatewayConstants.AM_APP_NAME_CACHEKEY); - String applicationName = GatewayDataHolder.getGatewayCache() - .getFromCache(GatewayCacheKey.of(cacheKey)).toString(); - - //Adding applicationName to contextProps for use in next steps - Map contextProps = obapiResponseContext.getContextProps(); - contextProps.put("AppName", applicationName); - obapiResponseContext.setContextProps(contextProps); - - //call application get endpoint to retrieve the application id - JsonElement applicationSearchResponse = - callGet(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), - GatewayConstants.BEARER_TAG.concat(token), "query", applicationName); - if (applicationSearchResponse == null) { - log.error("Error while searching application during delete"); - //delete IAM application used to invoke am rest endpoints - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), - basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - return; - } - - String applicationId = applicationSearchResponse.getAsJsonObject().get("list").getAsJsonArray().get(0) - .getAsJsonObject().get(applicationIdParam).getAsString(); - - if (!callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() - .concat("/").concat(applicationId), GatewayConstants.BEARER_TAG.concat(token))) { - log.error("Error while deleting AM application"); - //delete IAM application used to invoke am rest endpoints - callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), - basicAuthHeader); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - return; - } - - //delete IAM application used to invoke am rest endpoints - if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), - basicAuthHeader)) { - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - } - } catch (IOException | OpenBankingException | URISyntaxException e) { - log.error("Error occurred while deleting application", e); - handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); - } - } - } /** @@ -610,6 +254,427 @@ public void postProcessRequest(OBAPIRequestContext obapiRequestContext) { } } + /** + * Method to handle response for DCR POST requests. + * + * @param obapiResponseContext OB response context object + * @param basicAuthHeader Basic authentication header for accessing the DCR endpoint. + * @param fullBackEndURL URL of the OB DCR Endpoint + * @param regulatoryAPIs A map containing regulatory API names and the related authorized roles + */ + private void postProcessResponseForRegister(OBAPIResponseContext obapiResponseContext, String basicAuthHeader, + String fullBackEndURL, Map> regulatoryAPIs) { + + try { + JsonParser jsonParser = new JsonParser(); + JsonObject createdDCRAppDetails = ((JsonObject) jsonParser + .parse(obapiResponseContext.getResponsePayload())); + //get software statement from dcr app details + String softwareStatement = createdDCRAppDetails.has(OpenBankingConstants.SOFTWARE_STATEMENT) ? + createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT).toString() : null; + + //call IS DCR endpoint to create application for obtaining a token to invoke devportal REST APIs + JsonElement registrationResponse = createServiceProvider(basicAuthHeader, + createdDCRAppDetails.get("software_id").getAsString()); + if (registrationResponse == null) { + log.error("Error while creating AM app for invoking APIM rest apis"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + //call token endpoint to retrieve a token for invoking the devportal REST apis + String amRestAPIInvokeClientId = registrationResponse.getAsJsonObject() + .get(clientIdParam).getAsString(); + + String authHeaderForTokenRequest = GatewayUtils + .getBasicAuthHeader(registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(), + registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); + + JsonElement tokenResponse = getToken(authHeaderForTokenRequest, + urlMap.get(GatewayConstants.TOKEN_URL).toString(), amRestAPIInvokeClientId); + + if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { + log.error("Error while creating tokens"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); + String getSPDetails = urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(createdDCRAppDetails.get(clientIdParam).getAsString()); + //call IS dcr api to get client secret and client name + JsonElement createdSpDetails = callGet(getSPDetails, basicAuthHeader, "", ""); + if (createdSpDetails == null) { + log.error("Error while retrieving client id and secret"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + + //create am application + JsonObject amAppCreatePayload = getAppCreatePayload(createdSpDetails.getAsJsonObject() + .get("client_name").getAsString()); + JsonElement amApplicationCreateResponse = + callPost(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), + amAppCreatePayload.toString(), GatewayConstants.BEARER_TAG.concat(token)); + + if (amApplicationCreateResponse == null) { + log.error("Error while creating AM app"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + String keyMapURL = urlMap.get(GatewayConstants.KEY_MAP_URL).toString() + .replace("application-id", amApplicationCreateResponse.getAsJsonObject() + .get(applicationIdParam).getAsString()); + String keyManagerName = GatewayDataHolder.getInstance().getOpenBankingConfigurationService() + .getConfigurations().get(OpenBankingConstants.OB_KM_NAME).toString(); + + //map keys to am application + JsonObject keyMapPayload = getKeyMapPayload(createdDCRAppDetails.get(clientIdParam).getAsString(), + createdSpDetails.getAsJsonObject().get(clientSecret).getAsString(), + OpenBankingUtils.getSoftwareEnvironmentFromSSA(softwareStatement), keyManagerName); + + JsonElement amKeyMapResponse = callPost(keyMapURL, keyMapPayload.toString(), + GatewayConstants.BEARER_TAG.concat(token)); + if (amKeyMapResponse == null) { + log.error("Error while mapping keys to AM app"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + //delete AM application + callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() + .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() + .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + //get list of published APIs + JsonElement publishedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_RETRIEVE_URL).toString(), + GatewayConstants.BEARER_TAG.concat(token), "", ""); + if (publishedAPIsResponse == null) { + log.error("Error while retrieving published APIs"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + //delete AM application + callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() + .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() + .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + + List apiIDList = new ArrayList<>(); + if (regulatoryAPIs != null) { + if (StringUtils.isEmpty(softwareStatement)) { + apiIDList = filterRegulatoryAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() + .get(OpenBankingConstants.API_LIST).getAsJsonArray(), Collections.emptyList()); + } else { + apiIDList = filterRegulatoryAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() + .get(OpenBankingConstants.API_LIST).getAsJsonArray(), getRolesFromSSA(softwareStatement)); + } + } else { + log.warn("No regulatory APIs configured. Application will be subscribed to all published APIs"); + //subscribe to all APIs if there are no configured regulatory APIs + for (JsonElement apiInfo : publishedAPIsResponse.getAsJsonObject().get("list").getAsJsonArray()) { + apiIDList.add(apiInfo.getAsJsonObject().get("id").getAsString()); + } + } + //subscribe to apis + JsonArray subscribeAPIsPayload = getAPISubscriptionPayload(amApplicationCreateResponse + .getAsJsonObject().get(applicationIdParam).getAsString(), apiIDList); + JsonElement subscribeAPIsResponse = callPost(urlMap.get(GatewayConstants.API_SUBSCRIBE_URL).toString(), + subscribeAPIsPayload.toString(), "Bearer ".concat(token)); + if (subscribeAPIsResponse == null) { + log.error("Error while subscribing to APIs"); + String clientId = createdDCRAppDetails.get(clientIdParam).getAsString(); + //delete service provider + callDelete(fullBackEndURL.concat("/").concat(clientId), basicAuthHeader); + //delete SP created for calling dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader); + //delete AM application + callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() + .concat("/").concat(amApplicationCreateResponse.getAsJsonObject() + .get(applicationIdParam).getAsString()), GatewayConstants.BEARER_TAG.concat(token)); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + return; + } + + //delete IAM application used to invoke am rest endpoints + if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(amRestAPIInvokeClientId), basicAuthHeader)) { + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + } + + } catch (IOException | OpenBankingException | URISyntaxException | ParseException e) { + log.error("Error occurred while creating application", e); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + } + } + + /** + * Method to handle response for DCR PUT requests. + * + * @param obapiResponseContext OB response context object + * @param basicAuthHeader Basic authentication header for accessing the DCR endpoint. + * @param regulatoryAPIs A map containing regulatory API names and the related authorized roles + */ + private void postProcessResponseForUpdate(OBAPIResponseContext obapiResponseContext, String basicAuthHeader, + Map> regulatoryAPIs) { + + JsonParser jsonParser = new JsonParser(); + JsonObject createdDCRAppDetails = ((JsonObject) jsonParser.parse(obapiResponseContext + .getResponsePayload())); + try { + JsonObject dcrPayload = getIAMDCRPayload(createdDCRAppDetails.get("software_id").getAsString()); + JsonElement registrationResponse = callPost(urlMap.get(GatewayConstants.IAM_DCR_URL).toString(), + dcrPayload.toString(), basicAuthHeader); + if (registrationResponse == null) { + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + //call token endpoint to retrieve a token for invoking the devportal REST apis + String clientId = registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(); + String authHeaderForTokenRequest = GatewayUtils.getBasicAuthHeader(clientId, + registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); + + JsonElement tokenResponse = getToken(authHeaderForTokenRequest, + urlMap.get(GatewayConstants.TOKEN_URL).toString(), clientId); + if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { + log.error("Error while creating tokens"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); + + String applicationName = getApplicationName(obapiResponseContext.getResponsePayload(), + GatewayDataHolder.getInstance().getOpenBankingConfigurationService().getConfigurations()); + if (StringUtils.isEmpty(applicationName)) { + log.error("Error while retrieving application name during update"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + //call application get endpoint to retrieve the application id + JsonElement applicationSearchResponse = + callGet(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), + GatewayConstants.BEARER_TAG.concat(token), "query", applicationName); + if (applicationSearchResponse == null) { + log.error("Error while searching for created application during update"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + String applicationId = applicationSearchResponse.getAsJsonObject().get("list").getAsJsonArray().get(0) + .getAsJsonObject().get(applicationIdParam).getAsString(); + + //get list of subscribed APIs + JsonElement subscribedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString(), + GatewayConstants.BEARER_TAG.concat(token), "applicationId", applicationId); + if (subscribedAPIsResponse == null) { + log.error("Error while retrieving subscribed APIs"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + List subscribedAPIIdList = new ArrayList<>(); + for (JsonElement subscribedAPI : subscribedAPIsResponse.getAsJsonObject().get("list") + .getAsJsonArray()) { + String apiId = subscribedAPI.getAsJsonObject().get("apiId").getAsString(); + subscribedAPIIdList.add(apiId); + } + + //get software statement from dcr app details + String softwareStatement = createdDCRAppDetails.has(OpenBankingConstants.SOFTWARE_STATEMENT) ? + createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT).getAsString() : null; + if (StringUtils.isNotEmpty(softwareStatement)) { + final JsonArray subscribedAPIs = subscribedAPIsResponse.getAsJsonObject() + .get("list").getAsJsonArray(); + //check whether the ssa still contains the roles related to the subscribed APIs and unsubscribe if not + Optional.of(getRolesFromSSA(softwareStatement)) + .map(ssaRoles -> getUnAuthorizedAPIs(subscribedAPIs, regulatoryAPIs, ssaRoles)) + .flatMap(unAuthorizedApis -> unAuthorizedApis.stream() + .map(unAuthorizedApi -> String.format("%s/%s", + urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString(), unAuthorizedApi)) + .filter(endpoint -> isSubscriptionDeletionFailed(endpoint, GatewayConstants.BEARER_TAG + .concat(token))) + .findAny()) + .ifPresent(endpoint -> { + log.error("Error while unsubscribing from API: " + endpoint); + //delete SP created to call dev portal REST APIs + try { + callDelete(String.format("%s/%s", urlMap.get(GatewayConstants.IAM_DCR_URL).toString(), + clientId), basicAuthHeader); + } catch (OpenBankingException | IOException e) { + handleInternalServerError(obapiResponseContext, + OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR); + } + }); + } + //subscribe to new APIs if new roles were added to the SSA + //get list of published APIs + JsonElement publishedAPIsResponse = callGet(urlMap.get(GatewayConstants.API_RETRIEVE_URL).toString(), + GatewayConstants.BEARER_TAG.concat(token), "", ""); + if (publishedAPIsResponse == null) { + log.error("Error while retrieving published APIs"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + List apiIDList = new ArrayList<>(); + if (StringUtils.isEmpty(softwareStatement)) { + filterRegulatoryAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() + .get(OpenBankingConstants.API_LIST).getAsJsonArray(), Collections.emptyList()); + } else { + filterRegulatoryAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject() + .get(OpenBankingConstants.API_LIST).getAsJsonArray(), getRolesFromSSA(softwareStatement)); + } + + List newApisListToSubscribe = getNewAPIsToSubscribe(apiIDList, subscribedAPIIdList); + if (!newApisListToSubscribe.isEmpty()) { + JsonArray subscribeAPIsPayload = getAPISubscriptionPayload(applicationId, newApisListToSubscribe); + JsonElement subscribeAPIsResponse = callPost(urlMap.get(GatewayConstants.API_SUBSCRIBE_URL) + .toString(), subscribeAPIsPayload.toString(), "Bearer ".concat(token)); + if (subscribeAPIsResponse == null) { + log.error("Error while subscribing to APIs"); + //delete SP created to call dev portal REST APIs + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader); + handleInternalServerError(obapiResponseContext, + OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + return; + } + } + //delete IAM application used to invoke am rest endpoints + if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/") + .concat(clientId), basicAuthHeader)) { + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + } + } catch (ParseException | IOException | URISyntaxException | OpenBankingException e) { + log.error("Error occurred while creating application", e); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR); + } + } + + + /** + * Method to handle response for DCR DELETE requests. + * + * @param obapiResponseContext OB response context object + * @param basicAuthHeader Basic authentication header for accessing the DCR endpoint. + */ + private void postProcessResponseForDelete(OBAPIResponseContext obapiResponseContext, String basicAuthHeader) { + + try { + JsonObject dcrPayload = getIAMDCRPayload(obapiResponseContext.getApiRequestInfo().getConsumerKey()); + JsonElement registrationResponse = callPost(urlMap.get(GatewayConstants.IAM_DCR_URL).toString(), + dcrPayload.toString(), basicAuthHeader); + if (registrationResponse == null) { + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + return; + } + + //call token endpoint to retrieve a token for invoking the devportal REST apis + String clientId = registrationResponse.getAsJsonObject().get(clientIdParam).getAsString(); + String authHeaderForTokenRequest = GatewayUtils.getBasicAuthHeader(clientId, + registrationResponse.getAsJsonObject().get(clientSecret).getAsString()); + + JsonElement tokenResponse = getToken(authHeaderForTokenRequest, + urlMap.get(GatewayConstants.TOKEN_URL).toString(), clientId); + if (tokenResponse == null || tokenResponse.getAsJsonObject().get("access_token") == null) { + log.error("Error while creating tokens during delete"); + //delete IAM application used to invoke am rest endpoints + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), + basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + return; + } + String token = tokenResponse.getAsJsonObject().get("access_token").getAsString(); + + //get application id of the sent request + String cacheKey = obapiResponseContext.getApiRequestInfo().getConsumerKey() + .concat(GatewayConstants.AM_APP_NAME_CACHEKEY); + String applicationName = GatewayDataHolder.getGatewayCache() + .getFromCache(GatewayCacheKey.of(cacheKey)).toString(); + + //Adding applicationName to contextProps for use in next steps + Map contextProps = obapiResponseContext.getContextProps(); + contextProps.put("AppName", applicationName); + obapiResponseContext.setContextProps(contextProps); + + //call application get endpoint to retrieve the application id + JsonElement applicationSearchResponse = + callGet(urlMap.get(GatewayConstants.APP_CREATE_URL).toString(), + GatewayConstants.BEARER_TAG.concat(token), "query", applicationName); + if (applicationSearchResponse == null) { + log.error("Error while searching application during delete"); + //delete IAM application used to invoke am rest endpoints + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), + basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + return; + } + + String applicationId = applicationSearchResponse.getAsJsonObject().get("list").getAsJsonArray().get(0) + .getAsJsonObject().get(applicationIdParam).getAsString(); + + if (!callDelete(urlMap.get(GatewayConstants.APP_CREATE_URL).toString() + .concat("/").concat(applicationId), GatewayConstants.BEARER_TAG.concat(token))) { + log.error("Error while deleting AM application"); + //delete IAM application used to invoke am rest endpoints + callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), + basicAuthHeader); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + return; + } + + //delete IAM application used to invoke am rest endpoints + if (!callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/").concat(clientId), + basicAuthHeader)) { + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + } + } catch (IOException | OpenBankingException | URISyntaxException e) { + log.error("Error occurred while deleting application", e); + handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTATION_DELETE_ERROR); + } + } + private JsonObject getIAMDCRPayload(String uniqueId) { JsonObject jsonObject = new JsonObject(); @@ -716,20 +781,27 @@ protected JsonElement getToken(String authHeader, String url, String clientId) t } } - protected List filterRegulatorAPIs(Map> regulatoryAPINames, JsonArray publishedAPIs, - List softwareRoles) { + /** + * Filters the regulatory APIs based on the given software roles. + * + * @param regulatoryAPIs A map containing regulatory API names and their allowed roles + * @param publishedAPIs The list of published APIs as JSON array + * @param softwareRoles The list of software roles provided in the request + * @return A list of API IDs that the application is authorized to access + */ + protected List filterRegulatoryAPIs(Map> regulatoryAPIs, JsonArray publishedAPIs, + List softwareRoles) { List filteredAPIs = new ArrayList<>(); - for (JsonElement apiInfo : publishedAPIs) { - for (Map.Entry> entry : regulatoryAPINames.entrySet()) { - if (entry.getKey().equals(apiInfo.getAsJsonObject().get("name").getAsString())) { - List allowedRolesForAPI = entry.getValue(); - for (String allowedRole : allowedRolesForAPI) { - if (softwareRoles.contains(allowedRole)) { - filteredAPIs.add(apiInfo.getAsJsonObject().get("id").getAsString()); - break; - } - } + for (JsonElement publishedAPIInfo : publishedAPIs) { + String publishedAPIName = publishedAPIInfo.getAsJsonObject().get(OpenBankingConstants.API_NAME) + .getAsString(); + if (regulatoryAPIs.containsKey(publishedAPIName)) { + List allowedRolesForAPI = regulatoryAPIs.get(publishedAPIName); + // Check if no specific roles are configured for the API or if software roles contain any of the + // allowed roles + if (allowedRolesForAPI.isEmpty() || allowedRolesForAPI.stream().anyMatch(softwareRoles::contains)) { + filteredAPIs.add(publishedAPIInfo.getAsJsonObject().get(OpenBankingConstants.API_ID).getAsString()); } } } @@ -791,6 +863,22 @@ protected boolean callDelete(String endpoint, String authHeader) throws OpenBank } } + /** + * Check if the deletion of subscription at a given endpoint failed. + * + * @param endpoint The URL of the endpoint where the subscription deletion is attempted + * @param authHeader The authorization header to be used in the HTTP request + * @return True if the subscription deletion fails or an exception occurs, false otherwise + */ + protected boolean isSubscriptionDeletionFailed(String endpoint, String authHeader) { + + try { + return !callDelete(endpoint, GatewayConstants.BEARER_TAG.concat(authHeader)); + } catch (OpenBankingException | IOException e) { + return true; + } + } + private void handleBadRequestError(OBAPIRequestContext obapiRequestContext, String message) { //catch errors and set to context @@ -869,54 +957,33 @@ public List getRolesFromSSA(String softwareStatement) throws ParseExcept return softwareRoleList; } - /** - * Extract software_environment (SANDBOX or PRODUCTION) from SSA. - * - * @param softwareStatement software statement extracted from request payload - * @return software_environment - * @throws ParseException - */ - public String getSoftwareEnvironmentFromSSA(String softwareStatement) throws ParseException { - - String softwareEnvironment = IdentityConstants.PRODUCTION; - // decode software statement and get softwareEnvironment - JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, "body"); - Object softwareEnvironmentValue = - softwareStatementBody.get(OpenBankingConstants.SOFTWARE_ENVIRONMENT); - if (softwareEnvironmentValue != null && - softwareEnvironmentValue.toString().equalsIgnoreCase(IdentityConstants.SANDBOX)) { - softwareEnvironment = IdentityConstants.SANDBOX; - } - return softwareEnvironment; - } - protected String getApplicationName(String responsePayload, Map configurations) throws ParseException { - boolean isSoftwareIdAppName = Boolean.parseBoolean(configurations - .get(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME).toString()); - String applicationNameKey = configurations - .get(OpenBankingConstants.DCR_APPLICATION_NAME_KEY).toString(); - String applicationName = ""; JsonParser jsonParser = new JsonParser(); JsonObject createdDCRAppDetails = ((JsonObject) jsonParser.parse(responsePayload)); - String softwareStatement = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT) - .getAsString(); - JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, "body"); - //get application Name - if (isSoftwareIdAppName) { - if (softwareStatementBody.containsKey("software_id")) { - applicationName = softwareStatementBody.get("software_id").toString(); + String softwareStatement = createdDCRAppDetails.has(OpenBankingConstants.SOFTWARE_STATEMENT) ? + createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT).getAsString() : null; + boolean isSoftwareIdAppName = Boolean.parseBoolean(configurations + .get(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME).toString()); + String applicationNameKey = configurations.get(OpenBankingConstants.DCR_APPLICATION_NAME_KEY).toString(); + + // If a software statement is not provided, get the software id directly from created app details + if (StringUtils.isEmpty(softwareStatement)) { + if (isSoftwareIdAppName) { + return createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_ID).getAsString(); } } else { - if (softwareStatementBody.containsKey(applicationNameKey)) { - applicationName = softwareStatementBody.get(applicationNameKey).toString(); - } else { - applicationName = createdDCRAppDetails.get(applicationNameKey).toString(); + JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, + OpenBankingConstants.JWT_BODY); + if (isSoftwareIdAppName) { + //get software id form the software statement + return softwareStatementBody.get(OpenBankingConstants.SOFTWARE_ID).toString(); + } else if (softwareStatementBody.containsKey(applicationNameKey)) { + return softwareStatementBody.get(applicationNameKey).toString(); } } - - return applicationName; + return createdDCRAppDetails.get(applicationNameKey).getAsString(); } protected List getUnAuthorizedAPIs(JsonArray subscribedAPIs, Map> configuredAPIs, diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutor.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutor.java deleted file mode 100644 index 3bd11c33..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutor.java +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.gateway.executor.idempotency; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.error.OpenBankingErrorCodes; -import com.wso2.openbanking.accelerator.gateway.cache.OpenBankingIdempotencyCacheKey; -import com.wso2.openbanking.accelerator.gateway.cache.OpenBankingIdempotencyValidationCache; -import com.wso2.openbanking.accelerator.gateway.executor.core.OpenBankingGatewayExecutor; -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIRequestContext; -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIResponseContext; -import com.wso2.openbanking.accelerator.gateway.executor.model.OpenBankingExecutorError; -import com.wso2.openbanking.accelerator.gateway.util.GatewayConstants; -import com.wso2.openbanking.accelerator.gateway.util.IdempotencyConstants; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; - -import java.io.IOException; -import java.time.Duration; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -/** - * Executor to handle Payment Idempotency. - */ -public abstract class OpenBankingIdempotencyHandlingExecutor implements OpenBankingGatewayExecutor { - - private static final Log log = LogFactory.getLog(OpenBankingIdempotencyHandlingExecutor.class); - private OpenBankingIdempotencyValidationCache openBankingIdempotencyValidationCache = - OpenBankingIdempotencyValidationCache.getInstance(); - private OpenBankingConfigParser openBankingConfigParser = OpenBankingConfigParser.getInstance(); - - /** - * Method to handle pre request. - * - * @param obapiRequestContext OB request context object. - */ - @Override - public void preProcessRequest(OBAPIRequestContext obapiRequestContext) { - - } - - /** - * Method to handle post request. - * - * @param obapiRequestContext OB request context object. - */ - @Override - public void postProcessRequest(OBAPIRequestContext obapiRequestContext) { - - // Checking if idempotency is enabled. - if (!isIdempotencyEnabledFromConfig()) { - return; - } - - // Validating if the request is a valid idempotency available request. - if (!isValidIdempotencyRequest(obapiRequestContext)) { - return; - } - - //Retrieve headers and payload - Map requestHeaders = obapiRequestContext.getMsgInfo().getHeaders(); - - //Retrieve consumer key from headers - String consumerKey = obapiRequestContext.getApiRequestInfo().getConsumerKey(); - //Retrieve idempotency key from headers - String idempotencyKey = requestHeaders.get(getIdempotencyKeyConstantFromConfig()); - //Retrieve context properties - Map contextProps = obapiRequestContext.getContextProps(); - - // Retrieve elected resources - String resource = obapiRequestContext.getMsgInfo().getResource(); - - //Construct cache keys for request and response using client Id and idempotency key - String idempotencyCacheKey = consumerKey + "_" + resource + "_" + idempotencyKey; - - try { - Map payloadMap = getPayloadFromRequest(obapiRequestContext); - - String payload; - if (payloadMap.containsKey(IdempotencyConstants.PAYLOAD)) { - payload = (String) payloadMap.get(IdempotencyConstants.PAYLOAD); - } else { - log.error("Error reading payload, " + IdempotencyConstants.PAYLOAD + " is not set."); - return; - } - - int httpStatus; - if (payloadMap.containsKey(IdempotencyConstants.HTTP_STATUS)) { - httpStatus = (int) payloadMap.get(IdempotencyConstants.HTTP_STATUS); - } else { - log.error("Error reading HTTP status, " + IdempotencyConstants.HTTP_STATUS + " is not set."); - return; - } - - Map cachedObjectMap = getPropertiesFromCache(idempotencyCacheKey); - //Check whether the request exists in the cache - if (!cachedObjectMap.isEmpty()) { - log.debug("Handling idempotency through gateway"); - - // previous result is present in cache, retrieving request from cache - String cachedRequest = cachedObjectMap.get(GatewayConstants.REQUEST_CACHE_KEY); - String createdTime = cachedObjectMap.get(GatewayConstants.CREATED_TIME_CACHE_KEY); - //Check whether payload received is similar to the payload stored - if (isJSONPayloadSimilar(cachedRequest, payload)) { - log.debug("Payloads are similar for idempotent request"); - //Payloads are similar, hence checking whether request came within allowed time - if (isRequestReceivedWithinAllowedTime(createdTime)) { - log.debug("Idempotent request received within allowed time"); - //Retrieving the response from cache - String cachedResponse = cachedObjectMap.get(GatewayConstants.RESPONSE_CACHE_KEY); - - //Setting payload as modified payload - log.debug("Setting cached payload as the response"); - obapiRequestContext.setModifiedPayload(cachedResponse); - - //Setting Context Properties to return response without executing further - contextProps.put(GatewayConstants.IS_RETURN_RESPONSE, GatewayConstants.TRUE); - contextProps.put(GatewayConstants.MODIFIED_STATUS, String.valueOf(httpStatus)); - } - } else { - //Payloads are not similar, hence returning an error - log.error(IdempotencyConstants.Error.EXECUTOR_IDEMPOTENCY_KEY_FRAUDULENT); - obapiRequestContext.setError(true); - obapiRequestContext.setErrors(handleIdempotencyErrors(obapiRequestContext, - IdempotencyConstants.Error.EXECUTOR_IDEMPOTENCY_KEY_FRAUDULENT, - IdempotencyConstants.Error.HEADER_INVALID)); - } - } else { - log.debug("Request is not found in cache, adding the request to cache."); - //Since request is not in cache, adding the request to the cache against the idempotency key - contextProps.put(GatewayConstants.REQUEST_CACHE_KEY, payload); - } - } catch (IOException e) { - log.error(IdempotencyConstants.Error.EXECUTOR_IDEMPOTENCY_KEY_ERROR, e); - obapiRequestContext.setError(true); - obapiRequestContext.setErrors(handleIdempotencyErrors(obapiRequestContext, - IdempotencyConstants.Error.EXECUTOR_IDEMPOTENCY_KEY_ERROR, - IdempotencyConstants.Error.HEADER_INVALID)); - return; - } - //Adding idempotency key to the context properties - contextProps.put(GatewayConstants.IDEMPOTENCY_KEY_CACHE_KEY, idempotencyKey); - obapiRequestContext.setContextProps(contextProps); - } - - /** - * Method to handle pre response. - * - * @param obapiResponseContext OB response context object. - */ - @Override - public void preProcessResponse(OBAPIResponseContext obapiResponseContext) { - - } - - /** - * Method to handle post response. - * - * @param obapiResponseContext OB response context object. - */ - @Override - public void postProcessResponse(OBAPIResponseContext obapiResponseContext) { - - // Checking if idempotency is enabled. - if (!isIdempotencyEnabledFromConfig()) { - return; - } - - // Validating if the response is a valid idempotency available response. - if (!isValidIdempotencyResponse(obapiResponseContext)) { - return; - } - - //Retrieving payload - String responsePayload = obapiResponseContext.getResponsePayload(); - //Retrieve idempotency key from headers - String consumerKey = obapiResponseContext.getApiRequestInfo().getConsumerKey(); - //Retrieve context properties - Map contextProps = obapiResponseContext.getContextProps(); - - MsgInfoDTO msgInfoDTO = obapiResponseContext.getMsgInfo(); - - String idempotencyKey; - if (msgInfoDTO.getHeaders().get(getIdempotencyKeyConstantFromConfig()) != null) { - //Retrieve idempotency key from headers - idempotencyKey = msgInfoDTO.getHeaders().get(getIdempotencyKeyConstantFromConfig()); - } else { - //Retrieve idempotency key from context props if it does not exist as a header - idempotencyKey = contextProps.get(GatewayConstants.IDEMPOTENCY_KEY_CACHE_KEY); - } - - String createdTime = getCreatedTimeFromResponse(obapiResponseContext); - if (createdTime == null) { - log.error(IdempotencyConstants.Error.DATE_MISSING); - return; - } - - // Retrieve elected resources - String resource = msgInfoDTO.getResource(); - - //Construct cache keys for request and response using client Id and idempotency key - String idempotencyCacheKey = consumerKey + "_" + resource + "_" + idempotencyKey; - - //Add response and created time to the cache - HashMap cachedObject = getPropertiesFromCache(idempotencyCacheKey); - if (contextProps.get(GatewayConstants.REQUEST_CACHE_KEY) != null) { - cachedObject.put(GatewayConstants.REQUEST_CACHE_KEY, contextProps.get(GatewayConstants.REQUEST_CACHE_KEY)); - } - cachedObject.put(GatewayConstants.RESPONSE_CACHE_KEY, responsePayload); - cachedObject.put(GatewayConstants.CREATED_TIME_CACHE_KEY, createdTime); - - log.debug("Setting properties to cache"); - setPropertiesToCache(idempotencyCacheKey, cachedObject); - } - - /** - * Method to handle errors in Idempotency validation. - * - * @param obapiRequestContext obapiRequestContext. - * @param message message. - * @return Arraylist of OpenBankingExecutorError. - */ - protected ArrayList handleIdempotencyErrors(OBAPIRequestContext obapiRequestContext, - String message, String errorCode) { - - OpenBankingExecutorError error = new OpenBankingExecutorError(errorCode, - IdempotencyConstants.Error.IDEMPOTENCY_HANDLE_ERROR, message, - OpenBankingErrorCodes.BAD_REQUEST_CODE); - ArrayList executorErrors = obapiRequestContext.getErrors(); - executorErrors.add(error); - return executorErrors; - } - - /** - * Method to store properties to cache. - * - * @param key unique cache key. - * @param idempotentDetails properties to store. - */ - private void setPropertiesToCache(String key, HashMap idempotentDetails) { - - openBankingIdempotencyValidationCache.addToCache( - OpenBankingIdempotencyCacheKey.of(key), idempotentDetails); - } - - /** - * Method to retrieve context properties from cache. - * - * @param key unique cache key. - * @return context properties. - */ - private HashMap getPropertiesFromCache(String key) { - - HashMap cachedObject = openBankingIdempotencyValidationCache.getFromCache( - OpenBankingIdempotencyCacheKey.of(key)); - return cachedObject == null ? new HashMap<>() : cachedObject; - } - - /** - * Method to compare whether JSON payloads are equal. - * - * @param jsonString1 JSON payload retrieved from database - * @param jsonString2 JSON payload received from current request - * @return - * @throws IOException - */ - private boolean isJSONPayloadSimilar(String jsonString1, String jsonString2) throws IOException { - - JsonNode expectedNode = new ObjectMapper().readTree(jsonString1); - JsonNode actualNode = new ObjectMapper().readTree(jsonString2); - return expectedNode.equals(actualNode); - } - - /** - * Method to check whether difference between two dates is less than the configured time. - * - * @param createdTime Created Time of the request - * @return - */ - protected boolean isRequestReceivedWithinAllowedTime(String createdTime) { - - if (createdTime == null) { - return true; - } - String allowedTimeDuration = (String) openBankingConfigParser.getConfiguration() - .get(IdempotencyConstants.IDEMPOTENCY_ALLOWED_TIME); - if (allowedTimeDuration != null) { - OffsetDateTime createdDate = OffsetDateTime.parse(createdTime); - OffsetDateTime currDate = OffsetDateTime.now(createdDate.getOffset()); - - long diffInHours = Duration.between(createdDate, currDate).toMinutes(); - return diffInHours <= Long.parseLong(allowedTimeDuration); - } else { - log.error("Idempotency Allowed duration is null"); - return false; - } - } - - /** - * Method to check whether Idempotency handling is required. - * - * @return True if idempotency is required, else False. - */ - private boolean isIdempotencyEnabledFromConfig() { - - String isIdempotencyEnabled = (String) openBankingConfigParser.getConfiguration() - .get(IdempotencyConstants.IDEMPOTENCY_IS_ENABLED); - - return Boolean.parseBoolean(isIdempotencyEnabled); - } - - /** - * Method to get the Idempotency Key from the config. - * - * @return idempotency key. - */ - protected String getIdempotencyKeyConstantFromConfig() { - - return (String) openBankingConfigParser.getConfiguration() - .get(IdempotencyConstants.IDEMPOTENCY_KEY_HEADER); - } - - /** - * Method to get Created time from response. - * - * @param obapiResponseContext obapiResponseContext. - * @return created time. - */ - public abstract String getCreatedTimeFromResponse(OBAPIResponseContext obapiResponseContext); - - /** - * Method to get payload from request. - * - * @param obapiRequestContext obapiRequestContext. - * @return Map containing the payload and the http status. - */ - public abstract Map getPayloadFromRequest(OBAPIRequestContext obapiRequestContext); - - /** - * Method to check if the request is a valid idempotency request. - * - * @param obapiRequestContext obapiRequestContext. - * @return True if the request is valid, False if not. - */ - public abstract boolean isValidIdempotencyRequest(OBAPIRequestContext obapiRequestContext); - - /** - * Method to check if the method is a valid idempotency response. - * - * @param obapiResponseContext obapiResponseContext. - * @return True if the response is valid, False if not. - */ - public abstract boolean isValidIdempotencyResponse(OBAPIResponseContext obapiResponseContext); -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutor.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutor.java index a38ff066..f6ba7956 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutor.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutor.java @@ -20,6 +20,7 @@ import com.wso2.openbanking.accelerator.common.error.OpenBankingErrorCodes; import com.wso2.openbanking.accelerator.common.exception.CertificateValidationException; +import com.wso2.openbanking.accelerator.common.util.CertificateUtils; import com.wso2.openbanking.accelerator.common.util.Generated; import com.wso2.openbanking.accelerator.gateway.cache.CertificateRevocationCache; import com.wso2.openbanking.accelerator.gateway.cache.GatewayCacheKey; @@ -78,7 +79,7 @@ public void preProcessRequest(OBAPIRequestContext obapiRequestContext) { CertificateValidationUtils.handleExecutorErrors(error, obapiRequestContext); } else { X509Certificate transportCertificate = transportCert.get(); - if (CertificateValidationUtils.isExpired(transportCertificate)) { + if (CertificateUtils.isExpired(transportCertificate)) { LOG.error("Certificate with the serial number " + transportCertificate.getSerialNumber() + " issued by the CA " + transportCertificate.getIssuerDN().toString() + " is expired"); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIRequestContext.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIRequestContext.java index d7ec47f8..0ab7eb3b 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIRequestContext.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIRequestContext.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -62,10 +62,9 @@ public OBAPIRequestContext(RequestContextDTO requestContextDTO, Map contextProps, Map analyticsData) { this.requestContextDTO = requestContextDTO; - this.contextProps = contextProps; this.addedHeaders = new HashMap<>(); this.errors = new ArrayList<>(); - this.contextProps = new HashMap<>(); + this.contextProps = contextProps; this.analyticsData = analyticsData; Map headers = requestContextDTO.getMsgInfo().getHeaders(); @@ -253,7 +252,8 @@ public String getContextProperty(String key) { } private void handleContentTypeErrors(String errorCode, String errorMessage) { - OpenBankingExecutorError error = new OpenBankingExecutorError(errorCode, errorMessage, errorMessage, + OpenBankingExecutorError error = new OpenBankingExecutorError(errorCode, + OpenBankingErrorCodes.UNSUPPORTED_MEDIA_TYPE, errorMessage, OpenBankingErrorCodes.UNSUPPORTED_MEDIA_TYPE_CODE); this.isError = true; diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIResponseContext.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIResponseContext.java index a0a59214..2ca398bf 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIResponseContext.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/model/OBAPIResponseContext.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -188,7 +188,8 @@ public String getContextProperty(String key) { } private void handleContentTypeErrors(String errorCode, String errorMessage) { - OpenBankingExecutorError error = new OpenBankingExecutorError(errorCode, errorMessage, errorMessage, + OpenBankingExecutorError error = new OpenBankingExecutorError(errorCode, + OpenBankingErrorCodes.UNSUPPORTED_MEDIA_TYPE, errorMessage, OpenBankingErrorCodes.UNSUPPORTED_MEDIA_TYPE_CODE); this.isError = true; diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/revocation/OCSPValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/revocation/OCSPValidator.java index 471c5b72..8f0269b1 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/revocation/OCSPValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/revocation/OCSPValidator.java @@ -33,8 +33,8 @@ import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; +import org.bouncycastle.asn1.ASN1IA5String; import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; @@ -228,7 +228,7 @@ private static List getOcspUrlsFromAuthorityInfoAccess(AuthorityInformat GeneralName gn = accessDescription.getAccessLocation(); if (gn.getTagNo() == GeneralName.uniformResourceIdentifier) { - DERIA5String str = DERIA5String.getInstance(gn.getName()); + ASN1IA5String str = ASN1IA5String.getInstance(gn.getName()); String accessLocation = str.getString(); ocspUrlList.add(accessLocation); } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/util/CertificateValidationUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/util/CertificateValidationUtils.java index a2fb71ad..f1238d1e 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/util/CertificateValidationUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/executor/util/CertificateValidationUtils.java @@ -71,6 +71,10 @@ private CertificateValidationUtils() { // Adding a private constructor to hide the implicit public one. } + /** + * @deprecated use com.wso2.openbanking.accelerator.common.util.CertificateUtils.isExpired() instead + */ + @Deprecated public static boolean isExpired(X509Certificate peerCertificate) { try { peerCertificate.checkValidity(); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/handler/GatewayClientAuthenticationHandler.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/handler/GatewayClientAuthenticationHandler.java new file mode 100644 index 00000000..0ffe6650 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/handler/GatewayClientAuthenticationHandler.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + *

+ * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. + */ + +package com.wso2.openbanking.accelerator.gateway.handler; + +import com.wso2.openbanking.accelerator.common.error.OpenBankingErrorCodes; +import com.wso2.openbanking.accelerator.gateway.internal.GatewayDataHolder; +import com.wso2.openbanking.accelerator.gateway.util.GatewayConstants; +import com.wso2.openbanking.accelerator.gateway.util.GatewayUtils; +import org.apache.axis2.context.MessageContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.synapse.core.axis2.Axis2MessageContext; +import org.apache.synapse.rest.AbstractHandler; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Map; + +/** + * Handler to send transport certificate as a header to identity server. + * Responds with an error if the transport certificate is not found or malformed. + */ +public class GatewayClientAuthenticationHandler extends AbstractHandler { + + private static final Log log = LogFactory.getLog(GatewayClientAuthenticationHandler.class); + + @Override + public boolean handleRequest(org.apache.synapse.MessageContext messageContext) { + + log.debug("Gateway Client Authentication Handler engaged"); + MessageContext ctx = ((Axis2MessageContext) messageContext).getAxis2MessageContext(); + X509Certificate x509Certificate = GatewayUtils.extractAuthCertificateFromMessageContext(ctx); + Map headers = (Map) ctx.getProperty(MessageContext.TRANSPORT_HEADERS); + + if (x509Certificate != null) { + log.debug("Valid certificate found in request"); + try { + String certificateHeader = GatewayDataHolder.getInstance().getClientTransportCertHeaderName(); + String encodedCert = GatewayUtils.getPEMEncodedCertificateString(x509Certificate); + if (GatewayDataHolder.getInstance().isUrlEncodeClientTransportCertHeaderEnabled()) { + log.debug("URL encoding pem encoded transport certificate"); + encodedCert = URLEncoder.encode(encodedCert, "UTF-8"); + } + headers.put(certificateHeader, encodedCert); + ctx.setProperty(MessageContext.TRANSPORT_HEADERS, headers); + if (log.isDebugEnabled()) { + log.debug(String.format("Added encoded transport certificate in header %s", certificateHeader)); + } + } catch (CertificateEncodingException | UnsupportedEncodingException e) { + log.error("Unable to encode client transport certificate", e); + GatewayUtils.returnSynapseHandlerJSONError(messageContext, OpenBankingErrorCodes.BAD_REQUEST_CODE, + GatewayUtils.getOAuth2JsonErrorBody(GatewayConstants.INVALID_REQUEST, + GatewayConstants.TRANSPORT_CERT_MALFORMED)); + } + } else { + log.debug(GatewayConstants.TRANSPORT_CERT_NOT_FOUND); + GatewayUtils.returnSynapseHandlerJSONError(messageContext, OpenBankingErrorCodes.BAD_REQUEST_CODE, + GatewayUtils.getOAuth2JsonErrorBody(GatewayConstants.INVALID_REQUEST, + GatewayConstants.TRANSPORT_CERT_NOT_FOUND)); + } + return true; + } + + @Override + public boolean handleResponse(org.apache.synapse.MessageContext messageContext) { + + return true; + } + +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/internal/GatewayDataHolder.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/internal/GatewayDataHolder.java index 9918bc80..d67230ee 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/internal/GatewayDataHolder.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/internal/GatewayDataHolder.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -62,6 +62,8 @@ public class GatewayDataHolder { private boolean isAPIMAnalyticsEnabled; private boolean isOBDataPublishingEnabled; private String workerThreadCount; + private String clientTransportCertHeaderName; + private boolean isUrlEncodeClientTransportCertHeaderEnabled; private GatewayDataHolder() { @@ -136,6 +138,10 @@ public void setOpenBankingConfigurationService( setAPIMAnalyticsEnabled((String) configurations.get(DataPublishingConstants.APIM_ANALYTICS_ENABLED)); setOBDataPublishingEnabled((String) configurations.get(DataPublishingConstants.DATA_PUBLISHING_ENABLED)); setWorkerThreadCount((String) configurations.get(DataPublishingConstants.WORKER_THREAD_COUNT)); + setClientTransportCertHeaderName((String) configurations.get(OpenBankingConstants. + CLIENT_TRANSPORT_CERT_HEADER_NAME)); + setUrlEncodeClientTransportCertHeaderEnabled((String) configurations.get(OpenBankingConstants. + URL_ENCODE_CLIENT_TRANSPORT_CERT_HEADER_ENABLED)); } } @@ -342,4 +348,25 @@ public String getWorkerThreadCount() { return workerThreadCount; } + + public String getClientTransportCertHeaderName() { + + return clientTransportCertHeaderName; + } + + public void setClientTransportCertHeaderName(String clientTransportCertHeaderName) { + + this.clientTransportCertHeaderName = clientTransportCertHeaderName; + } + + public boolean isUrlEncodeClientTransportCertHeaderEnabled() { + + return isUrlEncodeClientTransportCertHeaderEnabled; + } + + public void setUrlEncodeClientTransportCertHeaderEnabled(String isUrlEncodeClientTransportCertHeaderEnabled) { + + this.isUrlEncodeClientTransportCertHeaderEnabled = + Boolean.parseBoolean(isUrlEncodeClientTransportCertHeaderEnabled); + } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/reporter/OBTimestampPublisher.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/reporter/OBTimestampPublisher.java index 3d78b638..4ac020ab 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/reporter/OBTimestampPublisher.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/reporter/OBTimestampPublisher.java @@ -25,6 +25,8 @@ import org.wso2.am.analytics.publisher.exception.MetricReportingException; import org.wso2.am.analytics.publisher.reporter.MetricEventBuilder; +import java.time.Duration; +import java.time.Instant; import java.util.HashMap; import java.util.Map; @@ -54,14 +56,16 @@ public void run() { try { Map eventMap = builder.build(); Map analyticsData = new HashMap<>(); + Object requestTimestamp = eventMap.get(REQUEST_TIMESTAMP); analyticsData.put(CORRELATION_ID, eventMap.get(CORRELATION_ID)); - analyticsData.put(REQUEST_TIMESTAMP, eventMap.get(REQUEST_TIMESTAMP)); + analyticsData.put(REQUEST_TIMESTAMP, requestTimestamp); analyticsData.put(BACKEND_LATENCY, eventMap.get(BACKEND_LATENCY) != null ? eventMap.get(BACKEND_LATENCY) : 0L); analyticsData.put(REQUEST_MEDIATION_LATENCY, eventMap.get(REQUEST_MEDIATION_LATENCY) != null ? eventMap.get(REQUEST_MEDIATION_LATENCY) : 0L); analyticsData.put(RESPONSE_LATENCY, - eventMap.get(RESPONSE_LATENCY) != null ? eventMap.get(RESPONSE_LATENCY) : 0L); + eventMap.get(RESPONSE_LATENCY) != null ? eventMap.get(RESPONSE_LATENCY) + : Duration.between(Instant.parse(requestTimestamp.toString()), Instant.now()).toMillis()); analyticsData.put(RESPONSE_MEDIATION_LATENCY, eventMap.get(RESPONSE_MEDIATION_LATENCY) != null ? eventMap.get(RESPONSE_MEDIATION_LATENCY) : 0L); publishLatencyData(analyticsData); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayConstants.java index ef40000a..9691cfed 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayConstants.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayConstants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -47,6 +47,9 @@ public class GatewayConstants { public static final String MODIFIED_STATUS = "ModifiedStatus"; public static final String APPLICATION = "application"; public static final String APPLICATION_USER = "application_user"; + public static final String AXIS2_MTLS_CERT_PROPERTY = "ssl.client.auth.cert.X509"; + public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----"; + public static final String END_CERT = "-----END CERTIFICATE-----"; //dcr related configs public static final String AM_APP_NAME_CACHEKEY = "APP_NAME"; @@ -97,6 +100,7 @@ public class GatewayConstants { // Error constants public static final String INVALID_CLIENT = "invalid_client"; + public static final String INVALID_REQUEST = "invalid_request"; public static final String CLIENT_CERTIFICATE_MISSING = "Invalid mutual TLS request. Client certificate is missing"; public static final String CLIENT_CERTIFICATE_INVALID = "Invalid mutual TLS request. Client certificate is invalid"; public static final String INVALID_GRANT_TYPE = "Access failure for API: grant type validation failed."; @@ -104,6 +108,8 @@ public class GatewayConstants { "correct security credentials "; public static final String MISSING_CREDENTIALS = "Invalid Credentials. Make sure your API invocation call " + "has a header - 'Authorization'"; + public static final String TRANSPORT_CERT_NOT_FOUND = "Valid transport certificate not found in the request"; + public static final String TRANSPORT_CERT_MALFORMED = "Provided transport certificate is malformed"; // Error codes public static final int API_AUTH_INVALID_CREDENTIALS = 900901; diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayUtils.java index eea7792a..15a10fdc 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/main/java/com/wso2/openbanking/accelerator/gateway/util/GatewayUtils.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -69,6 +69,8 @@ import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; import java.security.interfaces.ECPrivateKey; import java.util.ArrayList; import java.util.Base64; @@ -772,4 +774,56 @@ private static void sendSynapseHandlerFaultResponse(MessageContext messageContex axis2MC.removeProperty(Constants.Configuration.CONTENT_TYPE); Axis2Sender.sendBack(messageContext); } + + /** + * Method to get json error body in OAuth2 format. + * @return json error body + */ + public static String getOAuth2JsonErrorBody(String error, String errorDescription) { + + JSONObject errorJSON = new JSONObject(); + errorJSON.put("error", error); + errorJSON.put("error_description", errorDescription); + return errorJSON.toString(); + } + + /** + * Convert X509Certificate to PEM encoded string. + * + * @param certificate X509Certificate + * @return PEM encoded string + */ + public static String getPEMEncodedCertificateString(X509Certificate certificate) + throws CertificateEncodingException { + + StringBuilder certificateBuilder = new StringBuilder(); + Base64.Encoder encoder = Base64.getEncoder(); + byte[] encoded = certificate.getEncoded(); + String base64Encoded = encoder.encodeToString(encoded); + + certificateBuilder.append(GatewayConstants.BEGIN_CERT); + certificateBuilder.append(base64Encoded); + certificateBuilder.append(GatewayConstants.END_CERT); + + return certificateBuilder.toString().replaceAll("\n", "+"); + } + + /** + * Extract Certificate from Message Context. + * + * @param ctx Message Context + * @return X509Certificate + */ + public static X509Certificate extractAuthCertificateFromMessageContext( + org.apache.axis2.context.MessageContext ctx) { + + Object sslCertObject = ctx.getProperty(GatewayConstants.AXIS2_MTLS_CERT_PROPERTY); + if (sslCertObject != null) { + X509Certificate[] certs = (X509Certificate[]) sslCertObject; + return certs[0]; + } else { + return null; + } + } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutorTest.java index 144ea1a9..f790554d 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutorTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/dcr/DCRExecutorTest.java @@ -20,6 +20,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigurationService; import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; @@ -70,7 +71,7 @@ * Test for DCR executor. */ @PowerMockIgnore("jdk.internal.reflect.*") -@PrepareForTest({IdentityUtil.class, GatewayDataHolder.class}) +@PrepareForTest({IdentityUtil.class, GatewayDataHolder.class, OpenBankingConfigParser.class}) public class DCRExecutorTest { @Mock @@ -85,6 +86,9 @@ public class DCRExecutorTest { @Mock APIManagerConfiguration apiManagerConfiguration; + @Mock + OpenBankingConfigParser openBankingConfigParser; + @InjectMocks DCRExecutor dcrExecutor = new DCRExecutor(); @@ -282,6 +286,32 @@ public IObjectFactory getObjectFactory() { " \"id_token_signed_response_alg\": \"PS256\"\n" + "}"; + String dcrResponsePayloadWithoutSSA = "{\n" + + " \"software_id\": \"test12345\",\n" + + "\"client_name\" : \"sample app name\",\n" + + " \"grant_types\": [\n" + + " \"client_credentials\",\n" + + " \"authorization_code\",\n" + + " \"refresh_token\",\n" + + " \"urn:ietf:params:oauth:grant-type:jwt-bearer\"\n" + + " ],\n" + + " \"application_type\": \"web\",\n" + + " \"scope\": \"bank:accounts.basic:read bank:accounts.detail:read bank:transactions:read " + + "bank:payees:read bank:regular_payments:read common:customer.basic:read common:customer.detail:read" + + " cdr:registration\",\n" + + " \"client_id_issued_at\": 1619150285,\n" + + " \"redirect_uris\": [\n" + + " \"https://www.google.com/redirects/redirect1\",\n" + + " \"https://www.google.com/redirects/redirect2\"\n" + + " ],\n" + + " \"request_object_signing_alg\": \"PS256\",\n" + + " \"client_id\": \"uagAipmOU5quayzoznU1ddWg6tca\",\n" + + " \"token_endpoint_auth_method\": \"private_key_jwt\",\n" + + " \"response_types\": \"code id_token\",\n" + + " \"id_token_signed_response_alg\": \"PS256\"\n" + + "}"; + + @Test public void testFilterRegulatorAPIs() { @@ -301,9 +331,18 @@ public void testFilterRegulatorAPIs() { publishedAPIs.add(dcrApi); DCRExecutor dcrExecutor = new DCRExecutor(); - List filteredAPIList = dcrExecutor.filterRegulatorAPIs(configuredAPIList, publishedAPIs, dcrRoles); + List filteredAPIList = dcrExecutor.filterRegulatoryAPIs(configuredAPIList, publishedAPIs, dcrRoles); Assert.assertEquals(filteredAPIList.get(0), "1"); } + @Test + public void isSubscriptionDeletionFailed() throws OpenBankingException, IOException { + DCRExecutor dcrExecutor = Mockito.spy(DCRExecutor.class); + Mockito.doReturn(false).when(dcrExecutor) + .callDelete(Mockito.anyString(), anyString()); + boolean subscriptionDeletionFailed = dcrExecutor.isSubscriptionDeletionFailed(Mockito.anyString(), + Mockito.anyString()); + Assert.assertTrue(subscriptionDeletionFailed); + } @Test public void testExtractApplicationName() throws ParseException { @@ -316,7 +355,27 @@ public void testExtractApplicationName() throws ParseException { } @Test - public void testExtractApplicationNameWithSoftwateIDEnabledFalse() throws ParseException { + public void testExtractApplicationNameFromAppDetails() throws ParseException { + + Map configMap = new HashMap<>(); + configMap.put(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME, "true"); + configMap.put(OpenBankingConstants.DCR_APPLICATION_NAME_KEY, "software_client_name"); + String applicationName = dcrExecutor.getApplicationName(dcrResponsePayloadWithoutSSA, configMap); + Assert.assertEquals("test12345", applicationName); + } + + @Test + public void testExtractApplicationNameWhenSSANotContainsApplicationNameKey() throws ParseException { + + Map configMap = new HashMap<>(); + configMap.put(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME, "false"); + configMap.put(OpenBankingConstants.DCR_APPLICATION_NAME_KEY, "client_name"); + String applicationName = dcrExecutor.getApplicationName(dcrResponsePayloadWithoutSSA, configMap); + Assert.assertEquals("sample app name", applicationName); + } + + @Test + public void testExtractApplicationNameWithSoftwareIDEnabledFalse() throws ParseException { Map configMap = new HashMap<>(); configMap.put(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME, "false"); @@ -392,6 +451,10 @@ public void testNewAPIsToSubscribe() { @Test public void testPostProcessResponseForRegister() throws Exception { + PowerMockito.mockStatic(OpenBankingConfigParser.class); + Mockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); + Mockito.when(OpenBankingConfigParser.getInstance() + .getSoftwareEnvIdentificationSSAPropertyValueForSandbox()).thenReturn("sandbox"); OBAPIResponseContext obapiResponseContext = Mockito.mock(OBAPIResponseContext.class); MsgInfoDTO msgInfoDTO = Mockito.mock(MsgInfoDTO.class); DCRExecutor dcrExecutor = Mockito.spy(DCRExecutor.class); @@ -633,6 +696,10 @@ public void testErrorScenarios() throws IOException, OpenBankingException, URISy Mockito.doReturn(dcrResponsePayload).when(obapiResponseContext).getResponsePayload(); Mockito.when(openBankingConfigurationService.getAllowedAPIs()).thenReturn(configuredAPIList); + PowerMockito.mockStatic(OpenBankingConfigParser.class); + Mockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); + Mockito.when(OpenBankingConfigParser.getInstance().getSoftwareEnvIdentificationSSAPropertyValueForSandbox()) + .thenReturn("sandbox"); GatewayDataHolder.getInstance().setApiManagerConfiguration(apiManagerConfigurationService); Mockito.when(apiManagerConfigurationService.getAPIManagerConfiguration()).thenReturn(apiManagerConfiguration); Mockito.doReturn("admin").when(apiManagerConfiguration).getFirstProperty(anyString()); @@ -767,4 +834,5 @@ public void testErrorScenarios() throws IOException, OpenBankingException, URISy dcrExecutor.postProcessResponse(obapiResponseContext); verify(obapiResponseContext, times(8)).setError(true); } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorImpl.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorImpl.java deleted file mode 100644 index d6feeb91..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorImpl.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.gateway.executor.idempotency; - -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIRequestContext; -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIResponseContext; -import com.wso2.openbanking.accelerator.gateway.util.IdempotencyConstants; -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.MsgInfoDTO; - -import java.util.HashMap; -import java.util.Map; - - -/** - * OpenBankingIdempotencyHandlingExecutorImpl. - */ -public class OpenBankingIdempotencyHandlingExecutorImpl extends OpenBankingIdempotencyHandlingExecutor { - - private static final Log log = LogFactory.getLog(OpenBankingIdempotencyHandlingExecutorImpl.class); - - - @Override - public String getCreatedTimeFromResponse(OBAPIResponseContext obapiResponseContext) { - MsgInfoDTO msgInfoDTO = obapiResponseContext.getMsgInfo(); - String createdTime = null; - if (msgInfoDTO.getHeaders().get("CreatedTime") != null) { - //Retrieve response created time from headers - createdTime = msgInfoDTO.getHeaders().get("CreatedTime"); - } - return createdTime; - } - - @Override - public Map getPayloadFromRequest(OBAPIRequestContext obapiRequestContext) { - Map map = new HashMap<>(); - map.put(IdempotencyConstants.PAYLOAD, obapiRequestContext.getRequestPayload()); - map.put(IdempotencyConstants.HTTP_STATUS, HttpStatus.SC_CREATED); - return map; - } - - @Override - public boolean isValidIdempotencyRequest(OBAPIRequestContext obapiRequestContext) { - return true; - } - - @Override - public boolean isValidIdempotencyResponse(OBAPIResponseContext obapiResponseContext) { - return true; - } -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorTests.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorTests.java deleted file mode 100644 index 6af805f0..00000000 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/idempotency/OpenBankingIdempotencyHandlingExecutorTests.java +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.wso2.openbanking.accelerator.gateway.executor.idempotency; - -import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheConstants; -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedMember; -import com.wso2.openbanking.accelerator.gateway.cache.OpenBankingIdempotencyCacheKey; -import com.wso2.openbanking.accelerator.gateway.cache.OpenBankingIdempotencyValidationCache; -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIRequestContext; -import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIResponseContext; -import com.wso2.openbanking.accelerator.gateway.util.GatewayConstants; -import com.wso2.openbanking.accelerator.gateway.util.IdempotencyConstants; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.wso2.carbon.apimgt.common.gateway.dto.APIRequestInfoDTO; -import org.wso2.carbon.apimgt.common.gateway.dto.MsgInfoDTO; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; - -/** - ** Tests class for OpenBankingIdempotencyHandlingExecutor. - */ -@PowerMockIgnore({"jdk.internal.reflect.*", "javax.management.*"}) -@PrepareForTest({OpenBankingConfigParser.class}) -public class OpenBankingIdempotencyHandlingExecutorTests extends PowerMockTestCase { - - @Mock - OBAPIRequestContext obapiRequestContextMock; - - @Mock - OBAPIResponseContext obapiResponseContextMock; - - @Mock - MsgInfoDTO msgInfoDTO; - - @Mock - APIRequestInfoDTO apiRequestInfoDTO; - - @Mock - OpenBankingConfigParser openBankingConfigParser; - - String sampleIdempotencyKey = "a5ff9494-2a15-48f9-8ab4-05a10b91215b"; - String sampleConsumerKey = "dummykey"; - String sampleElectedResource = "/sampleElectedResource/1234"; - String sampleResponsePayload = "{\"transactionStatus\":\"RCVD\",\"chosenScaMethod\":" + - "[{\"name\":\"SMS OTP on Mobile\"," + - "\"authenticationType\":\"SMS_OTP\",\"explanation\":\"SMS based one time password\"," + - "\"authenticationMethodId\":\"sms-otp\"}],\"_links\":{\"scaStatus\":" + - "{\"href\":\"/v1/payments/sepa-credit-transfers/beecd66c-82ae-4ac8-9c04-9bd7c886d4a4/" + - "authorisations/1d5b6e3b-2180-4b4f-bb8c-054c597cb4e3\"},\"scaOAuth\":" + - "{\"href\":\"https://localhost:8243/.well-known/openid-configuration\"}," + - "\"self\":{\"href\":\"/v/payments/sepa-credit-transfers/beecd66c-82ae-4ac8-9c04-9bd7c886d4a4\"}," + - "\"status\":{\"href\":\"/v1/payments/sepa-credit-transfers/beecd66c-82ae-4ac8-9c04-9bd7c886d4a4" + - "/status\"}},\"paymentId\":\"beecd66c-82ae-4ac8-9c04-9bd7c886d4a4\"}"; - - DateTimeFormatter dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME; - ZonedDateTime zdt = ZonedDateTime.now(); - String sampleCreatedTime = dtf.format(zdt); - - String idempotencyCacheKeyHeader = "x-Idempotency-Key"; - - @BeforeClass - public void initClass() { - - MockitoAnnotations.initMocks(this); - } - - @Test(priority = 1) - public void testPostProcessResponse() { - - mockStatic(OpenBankingConfigParser.class); - when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); - - Map configuration = new HashMap<>(); - configuration.putAll(getDistributedCachingMockConfigurations()); - configuration.putAll(getIdempotencyMockConfigurations()); - Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configuration); - - PowerMockito.mockStatic(OpenBankingConfigParser.class); - PowerMockito.when(OpenBankingConfigParser.getInstance()) - .thenReturn(openBankingConfigParser); - - // Mocking response payload - when(obapiResponseContextMock.getResponsePayload()).thenReturn(sampleResponsePayload); - - // Mocking consumer key - when(obapiResponseContextMock.getApiRequestInfo()).thenReturn(apiRequestInfoDTO); - when(apiRequestInfoDTO.getConsumerKey()).thenReturn(sampleConsumerKey); - - // Mocking context props - Map contextProps = new HashMap<>(); - contextProps.put(GatewayConstants.REQUEST_CACHE_KEY, sampleResponsePayload); - contextProps.put(GatewayConstants.IDEMPOTENCY_KEY_CACHE_KEY, sampleIdempotencyKey); - when(obapiResponseContextMock.getContextProps()).thenReturn(contextProps); - - // Mocking response headers - when(obapiResponseContextMock.getMsgInfo()).thenReturn(msgInfoDTO); - Map responseHeaders = new HashMap<>(); - responseHeaders.put(idempotencyCacheKeyHeader, sampleIdempotencyKey); - responseHeaders.put("CreatedTime", sampleCreatedTime); - when(msgInfoDTO.getHeaders()).thenReturn(responseHeaders); - - // Mocking elected resource - when(msgInfoDTO.getResource()).thenReturn(sampleElectedResource); - - OpenBankingIdempotencyHandlingExecutorImpl openBankingIdempotencyHandlingExecutorImpl = - new OpenBankingIdempotencyHandlingExecutorImpl(); - openBankingIdempotencyHandlingExecutorImpl.postProcessResponse(obapiResponseContextMock); - - String cacheKey = sampleConsumerKey + "_" + sampleElectedResource + "_" + sampleIdempotencyKey; - HashMap expectedFromCache = new HashMap<>(); - expectedFromCache.put(GatewayConstants.REQUEST_CACHE_KEY, sampleResponsePayload); - expectedFromCache.put(GatewayConstants.RESPONSE_CACHE_KEY, sampleResponsePayload); - expectedFromCache.put(GatewayConstants.CREATED_TIME_CACHE_KEY, sampleCreatedTime); - - HashMap fromCache = OpenBankingIdempotencyValidationCache.getInstance() - .getFromCache(OpenBankingIdempotencyCacheKey.of(cacheKey)); - - Assert.assertEquals(fromCache, expectedFromCache); - } - - @Test(priority = 2) - public void testPostProcessRequest() { - - mockStatic(OpenBankingConfigParser.class); - when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); - - Map configuration = new HashMap<>(); - configuration.putAll(getDistributedCachingMockConfigurations()); - configuration.putAll(getIdempotencyMockConfigurations()); - Mockito.when(openBankingConfigParser.getConfiguration()).thenReturn(configuration); - - PowerMockito.mockStatic(OpenBankingConfigParser.class); - PowerMockito.when(OpenBankingConfigParser.getInstance()) - .thenReturn(openBankingConfigParser); - - when(obapiRequestContextMock.getRequestPayload()).thenReturn(sampleResponsePayload); - // Mocking request headers - when(obapiRequestContextMock.getMsgInfo()).thenReturn(msgInfoDTO); - Map requestHeaders = new HashMap<>(); - requestHeaders.put(idempotencyCacheKeyHeader, sampleIdempotencyKey); - when(msgInfoDTO.getHeaders()).thenReturn(requestHeaders); - - // Mocking elected resource - when(msgInfoDTO.getResource()).thenReturn(sampleElectedResource); - - // Mocking consumer key - when(obapiRequestContextMock.getApiRequestInfo()).thenReturn(apiRequestInfoDTO); - when(apiRequestInfoDTO.getConsumerKey()).thenReturn(sampleConsumerKey); - - OpenBankingIdempotencyHandlingExecutorImpl openBankingIdempotencyHandlingExecutorImpl = - new OpenBankingIdempotencyHandlingExecutorImpl(); - openBankingIdempotencyHandlingExecutorImpl.postProcessRequest(obapiRequestContextMock); - - } - - private Map getDistributedCachingMockConfigurations() { - - Map configuration = new HashMap<>(); - - configuration.put(OpenBankingDistributedCacheConstants.ENABLED, "true"); - configuration.put(OpenBankingDistributedCacheConstants.HOST_NAME, "localhost"); - configuration.put(OpenBankingDistributedCacheConstants.PORT, "5721"); - configuration.put(OpenBankingDistributedCacheConstants.DISCOVERY_MECHANISM, "Multicast"); - configuration.put(OpenBankingDistributedCacheConstants.MULTICAST_GROUP, "224.2.2.3"); - configuration.put(OpenBankingDistributedCacheConstants.MULTICAST_PORT, "54321"); - ArrayList interfaces = new ArrayList<>(); - interfaces.add("192.168.1.100-110"); - configuration.put(OpenBankingDistributedCacheConstants.TRUSTED_INTERFACES, interfaces); - configuration.put(OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MAX_HEARTBEAT, "600"); - configuration.put(OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MAX_MASTER_CONFIRMATION, "900"); - configuration.put(OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MERGE_FIRST_RUN_DELAY, "60"); - configuration.put(OpenBankingDistributedCacheConstants.HAZELCAST_PROPERTY_MERGE_NEXT_RUN_DELAY, "30"); - configuration.put(OpenBankingDistributedCacheConstants.PROPERTY_LOGGING_TYPE, "none"); - - return configuration; - } - - private Map getIdempotencyMockConfigurations() { - - Map configuration = new HashMap<>(); - configuration.put(IdempotencyConstants.IDEMPOTENCY_IS_ENABLED, "true"); - configuration.put(IdempotencyConstants.IDEMPOTENCY_CACHE_TIME_TO_LIVE, "1440"); - configuration.put(IdempotencyConstants.IDEMPOTENCY_KEY_HEADER, idempotencyCacheKeyHeader); - configuration.put(IdempotencyConstants.IDEMPOTENCY_ALLOWED_TIME, "24"); - - return configuration; - } - - @AfterClass - public void after() { - - OpenBankingDistributedMember.of().shutdown(); - } - -} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/error/handler/OBDefaultErrorHandlerTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/error/handler/OBDefaultErrorHandlerTest.java new file mode 100644 index 00000000..810e7b59 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/error/handler/OBDefaultErrorHandlerTest.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 com.wso2.openbanking.accelerator.gateway.executor.impl.error.handler; + +import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIRequestContext; +import com.wso2.openbanking.accelerator.gateway.executor.model.OBAPIResponseContext; +import com.wso2.openbanking.accelerator.gateway.executor.model.OpenBankingExecutorError; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Test class for OBDefaultErrorHandler. + */ +public class OBDefaultErrorHandlerTest { + + Map contextProps = new HashMap<>(); + + @Test + public void testPreRequestFlow() { + + OBAPIRequestContext obapiRequestContext = Mockito.mock(OBAPIRequestContext.class); + Mockito.when(obapiRequestContext.isError()).thenReturn(true); + Mockito.when(obapiRequestContext.getErrors()).thenReturn(getErrorList()); + Mockito.when(obapiRequestContext.getContextProps()).thenReturn(contextProps); + Mockito.when(obapiRequestContext.getAnalyticsData()).thenReturn(new HashMap<>()); + + OBDefaultErrorHandler commonReportingDataExecutor = Mockito.spy(OBDefaultErrorHandler.class); + commonReportingDataExecutor.preProcessRequest(obapiRequestContext); + verify(obapiRequestContext, times(0)).setError(false); + } + + @Test + public void testPostRequestFlow() { + + OBAPIRequestContext obapiRequestContext = Mockito.mock(OBAPIRequestContext.class); + Mockito.when(obapiRequestContext.isError()).thenReturn(true); + Mockito.when(obapiRequestContext.getErrors()).thenReturn(getErrorList()); + Mockito.when(obapiRequestContext.getContextProps()).thenReturn(contextProps); + Mockito.when(obapiRequestContext.getAnalyticsData()).thenReturn(new HashMap<>()); + + OBDefaultErrorHandler commonReportingDataExecutor = Mockito.spy(OBDefaultErrorHandler.class); + commonReportingDataExecutor.postProcessRequest(obapiRequestContext); + verify(obapiRequestContext, times(0)).setError(false); + } + + @Test + public void testPreResponseFlow() { + + OBAPIResponseContext obapiResponseContext = Mockito.mock(OBAPIResponseContext.class); + Mockito.when(obapiResponseContext.isError()).thenReturn(true); + Mockito.when(obapiResponseContext.getErrors()).thenReturn(getErrorList()); + Mockito.when(obapiResponseContext.getContextProps()).thenReturn(contextProps); + Mockito.when(obapiResponseContext.getAnalyticsData()).thenReturn(new HashMap<>()); + + OBDefaultErrorHandler commonReportingDataExecutor = Mockito.spy(OBDefaultErrorHandler.class); + commonReportingDataExecutor.preProcessResponse(obapiResponseContext); + verify(obapiResponseContext, times(0)).setError(false); + } + + @Test + public void testPostResponseFlow() { + + OBAPIResponseContext obapiResponseContext = Mockito.mock(OBAPIResponseContext.class); + Mockito.when(obapiResponseContext.isError()).thenReturn(true); + Mockito.when(obapiResponseContext.getErrors()).thenReturn(getErrorList()); + Mockito.when(obapiResponseContext.getContextProps()).thenReturn(contextProps); + Mockito.when(obapiResponseContext.getAnalyticsData()).thenReturn(new HashMap<>()); + + OBDefaultErrorHandler commonReportingDataExecutor = Mockito.spy(OBDefaultErrorHandler.class); + commonReportingDataExecutor.postProcessResponse(obapiResponseContext); + verify(obapiResponseContext, times(0)).setError(false); + } + + private ArrayList getErrorList() { + + OpenBankingExecutorError error = new OpenBankingExecutorError("400", "Invalid Request", + "Mandatory parameter is missing", "400"); + + ArrayList errors = new ArrayList<>(); + errors.add(error); + return errors; + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutorTest.java index 972fbe21..c9f7b963 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutorTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/java/com/wso2/openbanking/accelerator/gateway/executor/impl/mtls/cert/validation/executor/CertRevocationValidationExecutorTest.java @@ -20,6 +20,7 @@ import com.wso2.openbanking.accelerator.common.exception.CertificateValidationException; import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.CertificateUtils; import com.wso2.openbanking.accelerator.gateway.cache.CertificateRevocationCache; import com.wso2.openbanking.accelerator.gateway.cache.GatewayCacheKey; import com.wso2.openbanking.accelerator.gateway.executor.service.CertValidationService; @@ -81,7 +82,7 @@ public IObjectFactory getObjectFactory() { @Test(description = "When expired certificate is provided, then should return true") public void testIsCertValidWithExpiredCert() { - Assert.assertTrue(CertificateValidationUtils.isExpired(expiredPeerCertificate)); + Assert.assertTrue(CertificateUtils.isExpired(expiredPeerCertificate)); } @Test(description = "When certificate validation success, then should return false") diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/resources/testng.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/resources/testng.xml index 723ddc92..49169106 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/resources/testng.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.gateway/src/test/resources/testng.xml @@ -36,6 +36,7 @@ + @@ -57,11 +58,6 @@ - - - - - diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/pom.xml index f485600d..7e0acde5 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -40,7 +38,7 @@ org.eclipse.osgi - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -147,25 +145,37 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.data.publisher.common - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.throttler.dao - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.throttler.service + + org.wso2.carbon.identity.outbound.auth.push + org.wso2.carbon.identity.application.authenticator.push.device.handler + + + org.wso2.carbon.identity.outbound.auth.push + org.wso2.carbon.identity.application.authenticator.push + + + org.wso2.carbon.identity.outbound.auth.push + org.wso2.carbon.identity.application.authenticator.push.common + @@ -211,6 +221,8 @@ **/*PushAuthErrorResponse.class **/*DefaultSPMetadataFilter.class **/*IdentityServiceExporter.class + **/*DeviceVerificationToken.class + **/wrapper/* diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticator.java new file mode 100644 index 00000000..beb348c7 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticator.java @@ -0,0 +1,248 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app; + +import com.nimbusds.jwt.SignedJWT; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.exception.JWTValidationException; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.utils.App2AppAuthUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.authentication.framework.AbstractApplicationAuthenticator; +import org.wso2.carbon.identity.application.authentication.framework.FederatedApplicationAuthenticator; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; +import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.DeviceHandler; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerClientException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerServerException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.impl.DeviceHandlerImpl; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; + +import java.text.ParseException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * App2App authenticator for authenticating users from native auth attempt. + */ +public class App2AppAuthenticator extends AbstractApplicationAuthenticator + implements FederatedApplicationAuthenticator { + + private static final Log log = LogFactory.getLog(App2AppAuthenticator.class); + private static final long serialVersionUID = -5439464372188473141L; + private static DeviceHandler deviceHandler; + + /** + * Constructor for the App2AppAuthenticator. + */ + public App2AppAuthenticator() { + + if (deviceHandler == null) { + deviceHandler = new DeviceHandlerImpl(); + } + } + + /** + * This method is used to get authenticator name. + * + * @return String Authenticator name. + */ + @Override + public String getName() { + + return App2AppAuthenticatorConstants.AUTHENTICATOR_NAME; + } + + /** + * This method is used to get the friendly name of the authenticator. + * + * @return String Friendly name of the authenticator + */ + @Override + public String getFriendlyName() { + + return App2AppAuthenticatorConstants.AUTHENTICATOR_FRIENDLY_NAME; + } + + /** + * This method processes the authentication response received from the client. + * It verifies the authenticity of the received JWT token, extracts necessary information, + * and performs validations before authenticating the user. + * + * @param httpServletRequest The HTTP servlet request object containing the authentication response. + * @param httpServletResponse The HTTP servlet response object for sending responses. + * @param authenticationContext The authentication context containing information related to the authentication + * process. + * @throws AuthenticationFailedException If authentication fails due to various reasons such as missing parameters, + * parsing errors, JWT validation errors, or exceptions during authentication process. + */ + @Override + protected void processAuthenticationResponse(HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, + AuthenticationContext authenticationContext) + throws AuthenticationFailedException { + + authenticationContext.setCurrentAuthenticator(App2AppAuthenticatorConstants.AUTHENTICATOR_NAME); + String jwtString = + httpServletRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER); + String request = + httpServletRequest.getParameter(App2AppAuthenticatorConstants.REQUEST); + + try { + SignedJWT signedJWT = JWTUtils.getSignedJWT(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + //Extracting deviceId and loginHint is necessary to retrieve the public key + String loginHint = deviceVerificationToken.getLoginHint(); + String deviceID = deviceVerificationToken.getDeviceId(); + + //Checking whether deviceId and loginHint present in passed jwt + if (StringUtils.isBlank(loginHint) || StringUtils.isBlank(deviceID)) { + if (log.isDebugEnabled()) { + log.debug(App2AppAuthenticatorConstants.REQUIRED_PARAMS_MISSING_MESSAGE); + } + throw new AuthenticationFailedException(App2AppAuthenticatorConstants.REQUIRED_PARAMS_MISSING_MESSAGE); + } + + AuthenticatedUser userToBeAuthenticated = + App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(loginHint); + String publicKey = getPublicKeyByDeviceID(deviceID, userToBeAuthenticated); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(request); + // setting the user is mandatory for data publishing purposes + //If exception is thrown before setting a user data publishing will encounter exceptions + authenticationContext.setSubject(userToBeAuthenticated); + /* + if validations are failed it will throw a JWTValidationException and flow will be interrupted. + Hence, user Authentication will fail. + */ + App2AppAuthUtils.validateToken(deviceVerificationToken); + //If the flow is not interrupted user will be authenticated. + if (log.isDebugEnabled()) { + log.debug(String.format(App2AppAuthenticatorConstants.USER_AUTHENTICATED_MSG, + userToBeAuthenticated.getUserName())); + } + } catch (ParseException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException(App2AppAuthenticatorConstants.PARSE_EXCEPTION_MESSAGE, e); + } catch (JWTValidationException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException + (App2AppAuthenticatorConstants.APP_AUTH_IDENTIFIER_VALIDATION_EXCEPTION_MESSAGE, e); + } catch (OpenBankingException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException(App2AppAuthenticatorConstants.OPEN_BANKING_EXCEPTION_MESSAGE, e); + } catch (PushDeviceHandlerServerException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException + (App2AppAuthenticatorConstants.PUSH_DEVICE_HANDLER_SERVER_EXCEPTION_MESSAGE, e); + } catch (UserStoreException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException(App2AppAuthenticatorConstants.USER_STORE_EXCEPTION_MESSAGE, e); + } catch (PushDeviceHandlerClientException e) { + log.error(e.getMessage()); + throw new AuthenticationFailedException + (App2AppAuthenticatorConstants.PUSH_DEVICE_HANDLER_CLIENT_EXCEPTION_MESSAGE, e); + } catch (IllegalArgumentException e) { + log.error(e.getMessage()); + throw new + AuthenticationFailedException(App2AppAuthenticatorConstants.ILLEGAL_ARGUMENT_EXCEPTION_MESSAGE, e); + } + } + + /** + * Determines whether this authenticator can handle the incoming HTTP servlet request. + * This method checks if the request contains the necessary parameter for App2App authentication, + * which is the device verification token identifier. + * + * @param httpServletRequest The HTTP servlet request object to be checked for handling. + * @return True if this authenticator can handle the request, false otherwise. + */ + @Override + public boolean canHandle(HttpServletRequest httpServletRequest) { + + /* + App2App authenticates the user in one step depending on the app_auth_key, + Hence it's mandatory to have the required parameter app_auth_key. + */ + return StringUtils.isNotBlank(httpServletRequest.getParameter( + App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)); + } + + /** + * Retrieves the context identifier(sessionDataKey in this case) from the HTTP servlet request. + * + * @param request The HTTP servlet request object from which to retrieve the context identifier. + * @return The context identifier extracted from the request, typically representing session data key. + */ + @Override + public String getContextIdentifier(HttpServletRequest request) { + + return request.getParameter(App2AppAuthenticatorConstants.SESSION_DATA_KEY); + } + + /** + * Initiates the authentication request, but App2App authenticator does not support this operation. + * Therefore, this method terminates the authentication process and throws an AuthenticationFailedException. + * + * @param request The HTTP servlet request object. + * @param response The HTTP servlet response object. + * @param context The authentication context. + * @throws AuthenticationFailedException if this method is called + */ + @Override + protected void initiateAuthenticationRequest(HttpServletRequest request, + HttpServletResponse response, + AuthenticationContext context) + throws AuthenticationFailedException { + + /* + App2App authenticator does not support initiating authentication request, + Hence authentication process will be terminated. + */ + log.error(App2AppAuthenticatorConstants.INITIALIZATION_ERROR_MESSAGE); + throw new AuthenticationFailedException( + App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_MISSING_ERROR_MESSAGE); + } + + /** + * Retrieves the public key associated with a device and user. + * + * @param deviceID The identifier of the device for which the public key is requested. + * @param authenticatedUser the authenticated user for this request + * @return The public key associated with the specified device and user. + * @throws UserStoreException If an error occurs while accessing user store. + * @throws PushDeviceHandlerServerException If an error occurs on the server side of the push device handler. + * @throws PushDeviceHandlerClientException If an error occurs on the client side of the push device handler. + */ + private String getPublicKeyByDeviceID(String deviceID, AuthenticatedUser authenticatedUser) + throws UserStoreException, PushDeviceHandlerServerException, PushDeviceHandlerClientException, + OpenBankingException { + + UserRealm userRealm = App2AppAuthUtils.getUserRealm(authenticatedUser); + String userID = App2AppAuthUtils.getUserIdFromUsername(authenticatedUser.getUserName(), userRealm); + return App2AppAuthUtils.getPublicKey(deviceID, userID, deviceHandler); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorConstants.java new file mode 100644 index 00000000..b00f9c5a --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorConstants.java @@ -0,0 +1,51 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app; + +/** + * Constants related with App2App Authenticator process. + */ +public class App2AppAuthenticatorConstants { + + public static final String AUTHENTICATOR_NAME = "app2app"; + public static final String AUTHENTICATOR_FRIENDLY_NAME = "App2App Authenticator"; + public static final String REQUEST = "request"; + public static final String DEVICE_VERIFICATION_TOKEN_IDENTIFIER = "deviceVerificationToken"; + public static final String SESSION_DATA_KEY = "sessionDataKey"; + public static final String APP_AUTH_IDENTIFIER_VALIDATION_EXCEPTION_MESSAGE + = "Error while validating device verification token."; + public static final String ILLEGAL_ARGUMENT_EXCEPTION_MESSAGE + = "Error while creating user for provided login_hint."; + public static final String PARSE_EXCEPTION_MESSAGE = "Error while parsing the provided JWT."; + public static final String PUSH_DEVICE_HANDLER_SERVER_EXCEPTION_MESSAGE + = "Error occurred in push device handler service."; + public static final String USER_STORE_EXCEPTION_MESSAGE = "Error while creating authenticated user."; + public static final String PUSH_DEVICE_HANDLER_CLIENT_EXCEPTION_MESSAGE + = "Error occurred in Push Device handler client."; + public static final String INITIALIZATION_ERROR_MESSAGE = "Initializing App2App authenticator is not supported."; + public static final String DEVICE_VERIFICATION_TOKEN_MISSING_ERROR_MESSAGE + = "Device verification token null or empty in request."; + public static final String USER_AUTHENTICATED_MSG + = "User {%s} authenticated by app2app authenticator successfully."; + public static final String OPEN_BANKING_EXCEPTION_MESSAGE + = "Error while retrieving user."; + public static final String REQUIRED_PARAMS_MISSING_MESSAGE + = "Required Parameters did or loginHint null or empty."; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/cache/JTICache.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/cache/JTICache.java new file mode 100644 index 00000000..b32a8796 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/cache/JTICache.java @@ -0,0 +1,73 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.cache; + +import com.wso2.openbanking.accelerator.identity.cache.IdentityCache; +import com.wso2.openbanking.accelerator.identity.cache.IdentityCacheKey; + +/** + * Class for maintaining JTI cache. + */ +public class JTICache { + + private static volatile IdentityCache jtiCacheInstance; + + /** + * Get JTI cache instance. + * + * @return IdentityCache instance as JTICache + */ + public static IdentityCache getInstance() { + + //Outer null check avoids entering synchronized block when jtiCache is not null. + if (jtiCacheInstance == null) { + // Synchronize access to ensure thread safety + synchronized (JTICache.class) { + // Avoids race condition within threads + if (jtiCacheInstance == null) { + jtiCacheInstance = new IdentityCache(); + } + } + } + + return jtiCacheInstance; + } + + /** + * Adds the provided JTI (JSON Web Token ID) to the cache for efficient retrieval and management. + * + * @param jti The JTI (JSON Web Token ID) to be added to the cache. + */ + public static void addJtiDataToCache(String jti) { + + JTICache.getInstance().addToCache(IdentityCacheKey.of(jti), jti); + } + + /** + * Retrieves the data associated with the provided JTI (JSON Web Token ID) from the cache. + * + * @param jti The JTI (JSON Web Token ID) for which data is to be retrieved from the cache. + * @return The data associated with the provided JTI if found in the cache, otherwise null. + */ + public static Object getJtiDataFromCache(String jti) { + + return JTICache.getInstance().getFromCache(IdentityCacheKey.of(jti)); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/exception/JWTValidationException.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/exception/JWTValidationException.java new file mode 100644 index 00000000..e11dea70 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/exception/JWTValidationException.java @@ -0,0 +1,38 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.exception; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; + +/** + * DeviceVerificationToken Object Validation Exception. + */ +public class JWTValidationException extends OpenBankingException { + + private static final long serialVersionUID = -2572459527308720228L; + + public JWTValidationException(String message) { + super(message); + } + + public JWTValidationException(String message, Throwable e) { + super(message, e); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationToken.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationToken.java new file mode 100644 index 00000000..f977d161 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationToken.java @@ -0,0 +1,165 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.model; + +import com.google.gson.annotations.SerializedName; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateDigest; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateExpiry; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateJTI; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateNBF; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateSignature; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.MandatoryChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.SignatureCheck; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.ValidityChecks; + +import java.text.ParseException; +import java.util.Date; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * Model class for App2App Auth DeviceVerificationToken. + */ +@ValidateJTI(groups = ValidityChecks.class) +@ValidateSignature(groups = SignatureCheck.class) +@ValidateExpiry(groups = ValidityChecks.class) +@ValidateNBF(groups = ValidityChecks.class) +@ValidateDigest(groups = ValidityChecks.class) +public class DeviceVerificationToken { + + @SerializedName(DeviceVerificationTokenConstants.DEVICE_IDENTIFIER) + private String deviceId; + @SerializedName(DeviceVerificationTokenConstants.LOGIN_HINT) + private String loginHint; + @SerializedName(DeviceVerificationTokenConstants.EXPIRY_TIME) + private Date expirationTime; + @SerializedName(DeviceVerificationTokenConstants.NOT_VALID_BEFORE) + private Date notValidBefore; + @SerializedName(DeviceVerificationTokenConstants.JWT_ID) + private String jti; + @SerializedName(DeviceVerificationTokenConstants.ISSUED_TIME) + private Date issuedTime; + @SerializedName(DeviceVerificationTokenConstants.DIGEST) + private String digest; + private SignedJWT signedJWT; + private String publicKey; + private String requestObject; + + public DeviceVerificationToken(SignedJWT signedJWT) + throws ParseException { + + this.signedJWT = signedJWT; + JWTClaimsSet jwtClaimsSet = signedJWT.getJWTClaimsSet(); + this.expirationTime = jwtClaimsSet.getExpirationTime(); + this.notValidBefore = jwtClaimsSet.getNotBeforeTime(); + this.issuedTime = jwtClaimsSet.getIssueTime(); + this.jti = jwtClaimsSet.getJWTID(); + this.deviceId = getClaim(jwtClaimsSet, DeviceVerificationTokenConstants.DEVICE_IDENTIFIER); + this.loginHint = getClaim(jwtClaimsSet, DeviceVerificationTokenConstants.LOGIN_HINT); + this.digest = getClaim(jwtClaimsSet, DeviceVerificationTokenConstants.DIGEST); + } + + @NotBlank(message = "Required parameter did cannot be null or empty.", groups = MandatoryChecks.class) + public String getDeviceId() { + + return deviceId; + } + + @NotBlank(message = "Required parameter loginHint cannot be null or empty.", groups = MandatoryChecks.class) + public String getLoginHint() { + + return loginHint; + } + + @NotNull(message = "Required parameter exp cannot be null.", groups = MandatoryChecks.class) + public Date getExpirationTime() { + + return expirationTime; + } + + @NotNull(message = "Required parameter nbf cannot be null.", groups = MandatoryChecks.class) + public Date getNotValidBefore() { + + return notValidBefore; + } + + @NotBlank(message = "Required parameter jti cannot be null or empty.", groups = MandatoryChecks.class) + public String getJti() { + + return jti; + } + + @NotNull(message = "Required parameter iat cannot be null.", groups = MandatoryChecks.class) + public Date getIssuedTime() { + + return issuedTime; + } + + @NotNull(message = "Required parameter signedJWT cannot be null.", groups = MandatoryChecks.class) + public SignedJWT getSignedJWT() { + + return signedJWT; + } + + public void setSignedJWT(SignedJWT signedJWT) { + + this.signedJWT = signedJWT; + } + + @NotBlank(message = "Required parameter public key cannot be null or empty.", groups = MandatoryChecks.class) + public String getPublicKey() { + + return publicKey; + } + + public void setPublicKey(String publicKey) { + + this.publicKey = publicKey; + } + + public String getDigest() { + + return this.digest; + } + + /** + * Retrieves the value of the specified claim from the provided JWTClaimsSet. + * + * @param jwtClaimsSet the JWTClaimsSet from which to retrieve the claim value + * @param claim the name of the claim to retrieve + * @return the value of the specified claim, or null if the claim is not present + */ + private String getClaim(JWTClaimsSet jwtClaimsSet , String claim) { + + Object claimObj = jwtClaimsSet.getClaim(claim); + return (String) claimObj; + } + + public String getRequestObject() { + return requestObject; + } + + public void setRequestObject(String requestObject) { + this.requestObject = requestObject; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationTokenConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationTokenConstants.java new file mode 100644 index 00000000..c5c81664 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/model/DeviceVerificationTokenConstants.java @@ -0,0 +1,34 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.model; + +/** + * Constants for DeviceVerificationToken. + */ +public class DeviceVerificationTokenConstants { + + public static final String EXPIRY_TIME = "exp"; + public static final String NOT_VALID_BEFORE = "nbf"; + public static final String LOGIN_HINT = "login_hint"; + public static final String ISSUED_TIME = "ist"; + public static final String DEVICE_IDENTIFIER = "did"; + public static final String JWT_ID = "jti"; + public static final String DIGEST = "digest"; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/utils/App2AppAuthUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/utils/App2AppAuthUtils.java new file mode 100644 index 00000000..ec1efd4f --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/utils/App2AppAuthUtils.java @@ -0,0 +1,149 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.utils; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.validator.OpenBankingValidator; +import com.wso2.openbanking.accelerator.identity.app2app.exception.JWTValidationException; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.validationorder.App2AppValidationOrder; +import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.DeviceHandler; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerClientException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerServerException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.model.Device; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; + +import java.util.List; + +/** + * Utils class for Authentication related logic implementations. + */ +public class App2AppAuthUtils { + + /** + * Retrieves an authenticated user object based on the provided subject identifier. + * + * @param subjectIdentifier the subject identifier used to retrieve the authenticated user + * @return an AuthenticatedUser object representing the authenticated user + */ + public static AuthenticatedUser getAuthenticatedUserFromSubjectIdentifier(String subjectIdentifier) { + + return AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier(subjectIdentifier); + } + + /** + * Retrieves the user realm associated with the provided authenticated user. + * + * @param authenticatedUser the authenticated user for whom to retrieve the user realm + * @return the user realm associated with the authenticated user, or null if the user is not authenticated + * @throws UserStoreException if an error occurs while retrieving the user realm + */ + public static UserRealm getUserRealm(AuthenticatedUser authenticatedUser) throws UserStoreException { + + UserRealm userRealm = null; + + if (authenticatedUser != null) { + String tenantDomain = authenticatedUser.getTenantDomain(); + int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + RealmService realmService = IdentityExtensionsDataHolder.getInstance().getRealmService(); + userRealm = realmService.getTenantUserRealm(tenantId); + } + + return userRealm; + } + + /** + * Retrieves the user ID associated with the provided username from the specified user realm. + * + * @param username the username for which to retrieve the user ID + * @param userRealm the user realm from which to retrieve the user ID + * @return the user ID associated with the username + * @throws UserStoreException if an error occurs while retrieving the user ID + */ + public static String getUserIdFromUsername(String username, UserRealm userRealm) throws UserStoreException, + OpenBankingException { + + if (userRealm != null) { + AbstractUserStoreManager userStoreManager = (AbstractUserStoreManager) userRealm.getUserStoreManager(); + return userStoreManager.getUserIDFromUserName(username); + } else { + throw new OpenBankingException("UserRealm service can not be null."); + } + } + + /** + * Retrieve Public key of the device specified if it is registered under specified user. + * TODO: Optimise this code to retrieve device by did and validate userID. + * Github issue :{...} + * + * @param deviceId deviceId of the device where the public key is required + * @param userId userId of the user + * @return the public key of the intended device. + * @throws PushDeviceHandlerServerException if an error occurs on the server side while handling the device + * @throws IllegalArgumentException if the provided device identifier does not exist + * @throws PushDeviceHandlerClientException if an error occurs on the client side while handling the device + */ + public static String getPublicKey(String deviceId, String userId, DeviceHandler deviceHandler) + throws PushDeviceHandlerServerException, IllegalArgumentException, PushDeviceHandlerClientException, + OpenBankingException { + + /* + It is important to verify the device is registered under the given user + as public key is associated with device not the user. + */ + List deviceList = deviceHandler.listDevices(userId); + //If none of the devices registered under the given user matches the specified deviceId then throw a exception + deviceList.stream() + .filter(registredDevice -> StringUtils.equals(registredDevice.getDeviceId(), deviceId)) + .findFirst() + .orElseThrow(() -> + new OpenBankingException("Provided Device ID doesn't match any device registered under user.")); + //If a device is found retrieve and return the public key + return deviceHandler.getPublicKey(deviceId); + } + + /** + * Validator util to validate DeviceVerificationToken model for given validationOrder. + * + * @param deviceVerificationToken DeviceVerificationToken object that needs to be validated + * @throws JWTValidationException if validation failed + */ + public static void validateToken(DeviceVerificationToken deviceVerificationToken) throws JWTValidationException { + /* + App2AppValidationOrder validation order + 1.Required Params validation + 2.Validity Validations - Signature, JTI, Timeliness, Digest will be validated. + */ + String error = OpenBankingValidator.getInstance() + .getFirstViolation(deviceVerificationToken, App2AppValidationOrder.class); + + //if there is a validation violation convert it to JWTValidationException + if (error != null) { + throw new JWTValidationException(error); + } + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/DigestValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/DigestValidator.java new file mode 100644 index 00000000..6b9c0e4c --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/DigestValidator.java @@ -0,0 +1,105 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations; + +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateDigest; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * Validator class for validating digest of a device verification token. + * Digest here is expected to be the hash of the request object if it is present. + */ +public class DigestValidator implements ConstraintValidator { + + private static final Log log = LogFactory.getLog(DigestValidator.class); + + /** + * Checks if the given device verification token is valid based on its digest. + * + * @param deviceVerificationToken The device verification token to be validated. + * @param constraintValidatorContext The context in which the validation is performed. + * @return true if the token is valid, false otherwise. + */ + @Override + public boolean isValid(DeviceVerificationToken deviceVerificationToken, + ConstraintValidatorContext constraintValidatorContext) { + + String requestObject = deviceVerificationToken.getRequestObject(); + String digest = deviceVerificationToken.getDigest(); + return isDigestValid(digest, requestObject); + } + + /** + * Validating the digest of the requestObject. + * Digest is expected to be the hash of requestObject if request Object is not null. + * + * @param digest digest sent in the device verification token + * @param requestObject JWT String of the request object + * @return return true if the digest validation is a success, false otherwise + */ + protected boolean isDigestValid(String digest, String requestObject) { + + if (StringUtils.isBlank(requestObject)) { + //If the request is null nothing to validate. + return true; + } else if (StringUtils.isBlank(digest)) { + //If request is not empty and digest us empty validation fails. + return false; + } + + try { + // Example : SHA-256=EkH8fPgZ2TY2XGns8c5Vvce8h3DB83V+w47zHiyYfiQ= + String[] digestAttribute = digest.split("=", 2); + + if (digestAttribute.length != 2) { + log.error("Invalid digest."); + return false; + } + // Example : SHA-256 + String digestAlgorithm = digestAttribute[0].trim(); + String digestValue = digestAttribute[1].trim(); + MessageDigest messageDigest = MessageDigest.getInstance(digestAlgorithm); + byte[] digestHash = messageDigest.digest(requestObject.getBytes(StandardCharsets.UTF_8)); + String generatedDigest = Base64.getEncoder() + .encodeToString(digestHash); + + if (generatedDigest.equals(digestValue)) { + return true; + } + + } catch (NoSuchAlgorithmException e) { + log.error("Invalid algorithm.", e); + return false; + } + + return false; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/ExpiryValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/ExpiryValidator.java new file mode 100644 index 00000000..078fb847 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/ExpiryValidator.java @@ -0,0 +1,52 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations; + +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateExpiry; + +import java.util.Date; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * Validator class for validating expiry of a device verification token. + */ +public class ExpiryValidator implements ConstraintValidator { + + private static final long DEFAULT_TIME_SKEW_IN_SECONDS = 300L; + + /** + * Checks if the given device verification token is valid based on its expiration time. + * + * @param deviceVerificationToken The device verification token to be validated. + * @param constraintValidatorContext The context in which the validation is performed. + * @return true if the token is valid, false otherwise. + */ + @Override + public boolean isValid(DeviceVerificationToken deviceVerificationToken, + ConstraintValidatorContext constraintValidatorContext) { + + Date expiryTime = deviceVerificationToken.getExpirationTime(); + return JWTUtils.isValidExpiryTime(expiryTime, DEFAULT_TIME_SKEW_IN_SECONDS); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/JTIValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/JTIValidator.java new file mode 100644 index 00000000..960d67fd --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/JTIValidator.java @@ -0,0 +1,69 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations; + +import com.wso2.openbanking.accelerator.identity.app2app.cache.JTICache; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateJTI; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * Validator class for validating the JWT ID of a device verification token. + */ +public class JTIValidator implements ConstraintValidator { + + /** + * Checks if the given device verification token is valid based on its JTI value. + * + * @param deviceVerificationToken The device verification token to be validated. + * @param constraintValidatorContext The context in which the validation is performed. + * @return true if the token is valid, false otherwise. + */ + @Override + public boolean isValid(DeviceVerificationToken deviceVerificationToken, + ConstraintValidatorContext constraintValidatorContext) { + + String jti = deviceVerificationToken.getJti(); + return validateJTI(jti); + } + + private boolean validateJTI(String jti) { + + if (getFromCache(jti) != null) { + return false; + } + + //adding to cache to prevent the value from being replayed again + addToCache(jti); + return true; + } + + private Object getFromCache(String jti) { + + return JTICache.getJtiDataFromCache(jti); + } + + private void addToCache(String jti) { + + JTICache.addJtiDataToCache(jti); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/NBFValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/NBFValidator.java new file mode 100644 index 00000000..ff7b6528 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/NBFValidator.java @@ -0,0 +1,55 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations; + +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateNBF; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Date; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * Validation class for validating NBF of a device verification token. + */ +public class NBFValidator implements ConstraintValidator { + + private static final long DEFAULT_TIME_SKEW_IN_SECONDS = 300L; + private static final Log log = LogFactory.getLog(NBFValidator.class); + + /** + * Checks if the given device verification token is valid based on its nbf time. + * + * @param deviceVerificationToken The device verification token to be validated. + * @param constraintValidatorContext The context in which the validation is performed. + * @return true if the token is valid, false otherwise. + */ + @Override + public boolean isValid(DeviceVerificationToken deviceVerificationToken, + ConstraintValidatorContext constraintValidatorContext) { + + Date notValidBefore = deviceVerificationToken.getNotValidBefore(); + return JWTUtils.isValidNotValidBeforeTime(notValidBefore, DEFAULT_TIME_SKEW_IN_SECONDS); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/PublicKeySignatureValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/PublicKeySignatureValidator.java new file mode 100644 index 00000000..6ea59823 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/PublicKeySignatureValidator.java @@ -0,0 +1,77 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jwt.SignedJWT; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.validations.annotations.ValidateSignature; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * Validator class for validating the signature of a device verification token. + */ +public class PublicKeySignatureValidator implements ConstraintValidator { + + private static final Log log = LogFactory.getLog(PublicKeySignatureValidator.class); + + /** + * Checks if the given device verification token is valid based on its signature. + * + * @param deviceVerificationToken The device verification token to be validated. + * @param constraintValidatorContext The context in which the validation is performed. + * @return true if the token is valid, false otherwise. + */ + @Override + public boolean isValid(DeviceVerificationToken deviceVerificationToken, + ConstraintValidatorContext constraintValidatorContext) { + + SignedJWT signedJWT = deviceVerificationToken.getSignedJWT(); + String publicKey = deviceVerificationToken.getPublicKey(); + + try { + if (!JWTUtils.isValidSignature(signedJWT, publicKey)) { + log.error("Signature can't be verified with registered public key."); + return false; + } + } catch (NoSuchAlgorithmException e) { + log.error("No such algorithm found.", e); + return false; + } catch (InvalidKeySpecException e) { + log.error("Invalid key spec.", e); + return false; + } catch (JOSEException e) { + log.error("JOSE exception.", e); + return false; + } catch (OpenBankingException e) { + log.error("Algorithm not supported yet.", e); + } + return true; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateDigest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateDigest.java new file mode 100644 index 00000000..d50243c8 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateDigest.java @@ -0,0 +1,48 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.annotations; + +import com.wso2.openbanking.accelerator.identity.app2app.validations.DigestValidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation class for validating digest. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {DigestValidator.class}) +public @interface ValidateDigest { + + String message() default "Digest validation failed."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateExpiry.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateExpiry.java new file mode 100644 index 00000000..44134d4e --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateExpiry.java @@ -0,0 +1,48 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.annotations; + +import com.wso2.openbanking.accelerator.identity.app2app.validations.ExpiryValidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation class for validating expiry of a device verification token. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {ExpiryValidator.class}) +public @interface ValidateExpiry { + + String message() default "JWT token is expired."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateJTI.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateJTI.java new file mode 100644 index 00000000..24e33d67 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateJTI.java @@ -0,0 +1,48 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.annotations; + +import com.wso2.openbanking.accelerator.identity.app2app.validations.JTIValidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation class for validating JWT ID of a device verification token. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {JTIValidator.class}) +public @interface ValidateJTI { + + String message() default "JTI has been replayed"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateNBF.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateNBF.java new file mode 100644 index 00000000..c5c6ad02 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateNBF.java @@ -0,0 +1,48 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.annotations; + +import com.wso2.openbanking.accelerator.identity.app2app.validations.NBFValidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation class for validating NBF of a device verification token. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {NBFValidator.class}) +public @interface ValidateNBF { + + String message() default "JWT token is not active."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateSignature.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateSignature.java new file mode 100644 index 00000000..beaeb7a8 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/annotations/ValidateSignature.java @@ -0,0 +1,48 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.annotations; + +import com.wso2.openbanking.accelerator.identity.app2app.validations.PublicKeySignatureValidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation class for validating JWT Signature of a device verification token. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {PublicKeySignatureValidator.class}) +public @interface ValidateSignature { + + String message() default "Signature validation Failed."; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/validationorder/App2AppValidationOrder.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/validationorder/App2AppValidationOrder.java new file mode 100644 index 00000000..5619320b --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/app2app/validations/validationorder/App2AppValidationOrder.java @@ -0,0 +1,34 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.validations.validationorder; + +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.MandatoryChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.SignatureCheck; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.ValidityChecks; + +import javax.validation.GroupSequence; + +/** + * Class to define the order of execution for the hibernate validation groups. + */ +@GroupSequence({SignatureCheck.class , MandatoryChecks.class, ValidityChecks.class}) +public interface App2AppValidationOrder { + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/authenticator/OBIdentifierAuthenticator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/authenticator/OBIdentifierAuthenticator.java index 1710f41d..4eb4682d 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/authenticator/OBIdentifierAuthenticator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/authenticator/OBIdentifierAuthenticator.java @@ -515,6 +515,25 @@ private void appendRedirectUri(JSONObject sessionData) throws OpenBankingExcepti } } + /** + * Get redirect_uri using request_uri. + * + * @param requestUri - request_uri + * @return redirect_uri + * @throws OpenBankingException - OpenBankingException + */ + @Generated(message = "Excluding from code coverage since it requires a valid cache entry") + public String getRedirectUri(String requestUri) throws OpenBankingException { + + JSONObject requestObjectVal = getParRequestObject(requestUri); + if (requestObjectVal.has(REDIRECT_URI)) { + return requestObjectVal.get(REDIRECT_URI).toString(); + } else { + log.error("redirect_uri could not be found in the par request object."); + throw new OpenBankingException("redirect_uri could not be found in the par request object."); + } + } + /** * Retrieve PAR request object from session data cache. * @@ -526,10 +545,36 @@ private void appendRedirectUri(JSONObject sessionData) throws OpenBankingExcepti private JSONObject getParRequestObject(JSONObject sessionData) throws OpenBankingException { //get request ref Ex -> "IVL...." from "urn::IVL..." - String[] requestUri = sessionData.get(REQUEST_URI).toString().split(":"); - String requestUriRef = requestUri[requestUri.length - 1]; + String requestUri = sessionData.get(REQUEST_URI).toString(); + return getParRequestObject(requestUri); + } + + /** + * Retrieve PAR request object from request_uri. + * + * @param requestUri - request_uri + * @return Request object json. + * @throws OpenBankingException - OpenBankingException + */ + @Generated(message = "Excluding from code coverage since it requires a valid cache entry") + private JSONObject getParRequestObject(String requestUri) throws OpenBankingException { + + String[] requestUriArr = requestUri.split(":"); + String requestUriRef = requestUriArr[requestUriArr.length - 1]; + return getRequestObjectUsingUriReference(requestUriRef); + } + + /** + * Retrieve PAR request object using request_uri reference. + * + * @param requestUriReference - request_uri reference (i.e:last part of request_uri split by :) + * @return Request object json. + * @throws OpenBankingException - OpenBankingException + */ + @Generated(message = "Excluding from code coverage since it requires a valid cache entry") + private JSONObject getRequestObjectUsingUriReference(String requestUriReference) throws OpenBankingException { - SessionDataCacheKey cacheKey = new SessionDataCacheKey(requestUriRef); + SessionDataCacheKey cacheKey = new SessionDataCacheKey(requestUriReference); SessionDataCacheEntry cacheEntry = SessionDataCache.getInstance().getValueFromCache(cacheKey); if (cacheEntry != null) { @@ -543,8 +588,8 @@ private JSONObject getParRequestObject(JSONObject sessionData) throws OpenBankin } return new JSONObject(new String(requestObject, StandardCharsets.UTF_8)); } else { - log.error("Could not able to fetch par request object from session data cache."); - throw new OpenBankingException("Could not able to fetch par request object from session data cache."); + log.error("Unable to fetch par request object from session data cache."); + throw new OpenBankingException("Unable to fetch par request object from session data cache."); } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCacheKey.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/AttributeChecks.java similarity index 55% rename from open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCacheKey.java rename to open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/AttributeChecks.java index 639eaf35..4fd54abc 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.common/src/test/java/com/wso2/openbanking/accelerator/common/test/distributed/caching/TestOpenBankingDistributedCacheKey.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/AttributeChecks.java @@ -16,20 +16,13 @@ * under the License. */ -package com.wso2.openbanking.accelerator.common.test.distributed.caching; - -import com.wso2.openbanking.accelerator.common.distributed.caching.OpenBankingDistributedCacheKey; +package com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups; /** - * TestOpenBankingDistributedCacheKey. + * Interface for grouping the validation annotations. + * Groups the validations for attributes */ -public class TestOpenBankingDistributedCacheKey extends OpenBankingDistributedCacheKey { - - public TestOpenBankingDistributedCacheKey(String cacheKey) { - super(cacheKey); - } +public interface AttributeChecks { - public static OpenBankingDistributedCacheKey of(String cacheKey) { - return new TestOpenBankingDistributedCacheKey(cacheKey); - } } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/MandatoryChecks.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/MandatoryChecks.java new file mode 100644 index 00000000..6f2a082e --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/MandatoryChecks.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups; + +/** + * Interface for grouping the validation annotations. + * Grouping the mandatory check constraints + */ +public interface MandatoryChecks { + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/SignatureCheck.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/SignatureCheck.java new file mode 100644 index 00000000..25d302c6 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/SignatureCheck.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups; + +/** + * Interface for grouping the validation annotations. + * Groups the validation for signature + */ +public interface SignatureCheck { + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/ValidityChecks.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/ValidityChecks.java new file mode 100644 index 00000000..477db36a --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/common/annotations/validationgroups/ValidityChecks.java @@ -0,0 +1,28 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups; + +/** + * Interface for grouping the validation annotations. + * Groups the validations for the validity of a JWT + */ +public interface ValidityChecks { + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationRequest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationRequest.java index 658fd094..44663a5c 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationRequest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationRequest.java @@ -18,14 +18,14 @@ package com.wso2.openbanking.accelerator.identity.dcr.model; import com.google.gson.annotations.SerializedName; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.AttributeChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.MandatoryChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.SignatureCheck; import com.wso2.openbanking.accelerator.identity.dcr.validation.DCRCommonConstants; import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateAlgorithm; import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateIssuer; import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateRequiredParams; import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateSignature; -import com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups.AttributeChecks; -import com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups.MandatoryChecks; -import com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups.SignatureCheck; import java.util.List; import java.util.Map; @@ -54,6 +54,9 @@ public class RegistrationRequest { @SerializedName("token_endpoint_auth_method") private String tokenEndPointAuthMethod; + @SerializedName("jwks_uri") + private String jwksURI; + @SerializedName("grant_types") private List grantTypes; @@ -353,4 +356,11 @@ public void setJti(String jti) { this.jti = jti; } + public String getJwksURI() { + return jwksURI; + } + + public void setJwksURI(String jwksURI) { + this.jwksURI = jwksURI; + } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationResponse.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationResponse.java index 080b9765..8078f34a 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationResponse.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/model/RegistrationResponse.java @@ -69,6 +69,9 @@ public void setToken(String token) { @SerializedName("software_id") protected String softwareId = null; + @SerializedName("jwks_uri") + private String jwksURI; + @SerializedName("token_endpoint_auth_method") protected String tokenEndpointAuthMethod = null; @@ -206,4 +209,12 @@ public String getRegistrationClientURI() { public void setRegistrationClientURI(String registrationClientURI) { this.registrationClientURI = registrationClientURI; } + + public String getJwksURI() { + return jwksURI; + } + + public void setJwksURI(String jwksURI) { + this.jwksURI = jwksURI; + } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/utils/ValidatorUtils.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/utils/ValidatorUtils.java index 823b8d10..ec7b9c92 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/utils/ValidatorUtils.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/utils/ValidatorUtils.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidator.java index 8d7e45bd..a7dfc3ef 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidator.java @@ -47,13 +47,12 @@ public void initialize(ValidateIssuer validateIssuer) { } @Override - public boolean isValid(Object registrationRequest, - ConstraintValidatorContext constraintValidatorContext) { + public boolean isValid(Object registrationRequest, ConstraintValidatorContext constraintValidatorContext) { try { String issuer = BeanUtils.getProperty(registrationRequest, issuerPath); - if (issuer != null) { - String softwareStatement = BeanUtils.getProperty(registrationRequest, ssaPath); + String softwareStatement = BeanUtils.getProperty(registrationRequest, ssaPath); + if (issuer != null && softwareStatement != null) { String softwareId = JWTUtils.decodeRequestJWT(softwareStatement, "body") .getAsString(DCRCommonConstants.SOFTWARE_ID); if (softwareId != null && softwareId.equals(issuer)) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidator.java index 12a96b96..2b37bc65 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidator.java @@ -69,7 +69,7 @@ public boolean isValid(Object registrationRequestObject, ConstraintValidatorCont .addConstraintViolation(); return false; } - //validate string type required parameters + //validate list type required parameters if (requestParameterMap.get(camelCaseConfigParam) instanceof List) { List param = (List) requestParameterMap.get(camelCaseConfigParam); if (param.isEmpty()) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/SignatureValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/SignatureValidator.java index 6d53da5c..0c5dd3f0 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/SignatureValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/SignatureValidator.java @@ -20,10 +20,13 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.proc.BadJOSEException; import com.nimbusds.jwt.SignedJWT; +import com.wso2.openbanking.accelerator.common.identity.IdentityConstants; import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.common.util.OpenBankingUtils; import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateSignature; import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,31 +59,34 @@ public boolean isValid(Object registrationRequest, ConstraintValidatorContext constraintValidatorContext) { try { - - boolean isValidSignature = false; - SignedJWT signedJWT = SignedJWT.parse(BeanUtils.getProperty(registrationRequest, softwareStatementPath)); + String softwareStatement = BeanUtils.getProperty(registrationRequest, softwareStatementPath); + if (StringUtils.isEmpty(softwareStatement)) { + return true; + } + SignedJWT signedJWT = SignedJWT.parse(softwareStatement); String jwtString = signedJWT.getParsedString(); String alg = signedJWT.getHeader().getAlgorithm().getName(); + String softwareEnvironmentFromSSA = OpenBankingUtils.getSoftwareEnvironmentFromSSA(jwtString); + String jwksURL; - // first validate the signature against production jwks - String jwksURL = IdentityExtensionsDataHolder.getInstance().getConfigurationMap() - .get(DCRCommonConstants.DCR_JWKS_ENDPOINT_PRODUCTION).toString(); - if (log.isDebugEnabled()) { - log.debug(String.format("Validating the signature from Production JwksUrl %s", jwksURL)); - } - isValidSignature = isValidateJWTSignature(jwksURL, jwtString, alg); - - if (!isValidSignature) { + if (IdentityConstants.PRODUCTION.equals(softwareEnvironmentFromSSA)) { + // validate the signature against production jwks + jwksURL = IdentityExtensionsDataHolder.getInstance().getConfigurationMap() + .get(DCRCommonConstants.DCR_JWKS_ENDPOINT_PRODUCTION).toString(); + if (log.isDebugEnabled()) { + log.debug(String.format("Validating the signature from Production JwksUrl %s", + jwksURL.replaceAll("[\r\n]", ""))); + } + } else { // else validate the signature against sandbox jwks jwksURL = IdentityExtensionsDataHolder.getInstance().getConfigurationMap() .get(DCRCommonConstants.DCR_JWKS_ENDPOINT_SANDBOX).toString(); if (log.isDebugEnabled()) { - log.debug(String.format("Could not validate the signature from Production JwksUrl, " + - "Trying with Sandbox JwksUrl %s", jwksURL)); + log.debug(String.format("Validating the signature from Sandbox JwksUrl %s", + jwksURL.replaceAll("[\r\n]", ""))); } - isValidSignature = isValidateJWTSignature(jwksURL, jwtString, alg); } - return isValidSignature; + return isValidateJWTSignature(jwksURL, jwtString, alg); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { log.error("Error while resolving validation fields", e); } catch (ParseException e) { @@ -101,3 +107,4 @@ private boolean isValidateJWTSignature(String jwksURL, String jwtString, String return false; } } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/AttributeChecks.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/AttributeChecks.java index 37537bd2..f65793bf 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/AttributeChecks.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/AttributeChecks.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -15,12 +15,15 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups; /** * Interface for grouping the validation annotations. * Groups the validations for attributes */ +@Deprecated public interface AttributeChecks { } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/MandatoryChecks.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/MandatoryChecks.java index 5c90e4eb..cb938dbb 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/MandatoryChecks.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/MandatoryChecks.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -15,12 +15,15 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups; /** * Interface for grouping the validation annotations. * Grouping the mandatory check constraints */ +@Deprecated public interface MandatoryChecks { } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/SignatureCheck.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/SignatureCheck.java index 5faefd7a..4ce4bacb 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/SignatureCheck.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/SignatureCheck.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -15,12 +15,15 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups; /** * Interface for grouping the validation annotations. * Groups the validation for signature */ +@Deprecated public interface SignatureCheck { } + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidationOrder.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidationOrder.java index fa2ef63d..d42af484 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidationOrder.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidationOrder.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -23,6 +23,7 @@ * Class to define the order of execution for the hibernate validation groups. */ @GroupSequence({MandatoryChecks.class, AttributeChecks.class, SignatureCheck.class}) +@Deprecated public interface ValidationOrder { } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidityChecks.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidityChecks.java new file mode 100644 index 00000000..4a011cca --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationgroups/ValidityChecks.java @@ -0,0 +1,29 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups; + +/** + * Interface for grouping the validation annotations. + * Groups the validations for the validity of a JWT + */ +@Deprecated +public interface ValidityChecks { + +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationorder/ValidationOrder.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationorder/ValidationOrder.java new file mode 100644 index 00000000..9a2355a4 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/validation/validationorder/ValidationOrder.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.wso2.openbanking.accelerator.identity.dcr.validation.validationorder; + +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.AttributeChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.MandatoryChecks; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.SignatureCheck; + +import javax.validation.GroupSequence; + +/** + * Class to define the order of execution for the hibernate validation groups. + */ +@GroupSequence({MandatoryChecks.class, AttributeChecks.class, SignatureCheck.class}) +public interface ValidationOrder { + +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute.resolution/DisputeResolutionFilter.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute/resolution/DisputeResolutionFilter.java similarity index 99% rename from open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute.resolution/DisputeResolutionFilter.java rename to open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute/resolution/DisputeResolutionFilter.java index a0583fe1..d8bbcda7 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute.resolution/DisputeResolutionFilter.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/dispute/resolution/DisputeResolutionFilter.java @@ -146,6 +146,3 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha } - - - diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/interceptor/OBIntrospectionDataProvider.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/interceptor/OBIntrospectionDataProvider.java index 310a93f2..5429a6ec 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/interceptor/OBIntrospectionDataProvider.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/interceptor/OBIntrospectionDataProvider.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -27,7 +27,6 @@ import org.wso2.carbon.identity.oauth2.dto.OAuth2IntrospectionResponseDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; -import java.util.Collections; import java.util.Map; /** @@ -41,14 +40,17 @@ public class OBIntrospectionDataProvider extends AbstractIdentityHandler impleme public Map getIntrospectionData(OAuth2TokenValidationRequestDTO oAuth2TokenValidationRequestDTO, OAuth2IntrospectionResponseDTO oAuth2IntrospectionResponseDTO) throws IdentityOAuth2Exception { + + Map additionalDataMap = getIntrospectionDataProvider() + .getIntrospectionData(oAuth2TokenValidationRequestDTO, oAuth2IntrospectionResponseDTO); String[] nonInternalScopes = IdentityCommonUtil.removeInternalScopes(oAuth2IntrospectionResponseDTO.getScope() .split(IdentityCommonConstants.SPACE_SEPARATOR)); oAuth2IntrospectionResponseDTO.setScope(StringUtils.join(nonInternalScopes, IdentityCommonConstants.SPACE_SEPARATOR)); - oAuth2IntrospectionResponseDTO.setProperties(Collections.singletonMap(IdentityCommonConstants.SCOPE, - StringUtils.join(nonInternalScopes, IdentityCommonConstants.SPACE_SEPARATOR))); - return getIntrospectionDataProvider().getIntrospectionData(oAuth2TokenValidationRequestDTO, - oAuth2IntrospectionResponseDTO); + additionalDataMap.put(IdentityCommonConstants.SCOPE, StringUtils.join(nonInternalScopes, + IdentityCommonConstants.SPACE_SEPARATOR)); + oAuth2IntrospectionResponseDTO.setProperties(additionalDataMap); + return additionalDataMap; } public static IntrospectionDataProvider getIntrospectionDataProvider() { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/internal/IdentityExtensionsServiceComponent.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/internal/IdentityExtensionsServiceComponent.java index 8d0ce104..a1f76804 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/internal/IdentityExtensionsServiceComponent.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/internal/IdentityExtensionsServiceComponent.java @@ -20,6 +20,7 @@ import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigurationService; import com.wso2.openbanking.accelerator.consent.mgt.service.ConsentCoreService; +import com.wso2.openbanking.accelerator.identity.app2app.App2AppAuthenticator; import com.wso2.openbanking.accelerator.identity.auth.extensions.adaptive.function.OpenBankingAuthenticationWorkerFunction; import com.wso2.openbanking.accelerator.identity.auth.extensions.adaptive.function.OpenBankingAuthenticationWorkerFunctionImpl; import com.wso2.openbanking.accelerator.identity.authenticator.OBIdentifierAuthenticator; @@ -85,11 +86,16 @@ protected void activate(ComponentContext context) { new OBIdentifierAuthenticator(), null); bundleContext.registerService(ClaimProvider.class.getName(), new RoleClaimProviderImpl(), null); bundleContext.registerService(OAuthEventInterceptor.class, new TokenRevocationListener(), null); + App2AppAuthenticator app2AppAuthenticator = new App2AppAuthenticator(); + bundleContext.registerService(ApplicationAuthenticator.class.getName(), + app2AppAuthenticator, null); - JsFunctionRegistry jsFunctionRegistry = IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry(); - OpenBankingAuthenticationWorkerFunction worker = new OpenBankingAuthenticationWorkerFunctionImpl(); - jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "OBAuthenticationWorker", - worker); + if (IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry() != null) { + JsFunctionRegistry jsFunctionRegistry = IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry(); + OpenBankingAuthenticationWorkerFunction worker = new OpenBankingAuthenticationWorkerFunctionImpl(); + jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "OBAuthenticationWorker", + worker); + } } @@ -247,15 +253,17 @@ public void unsetOAuth2Service(OAuth2Service oAuth2Service) { @Deactivate protected void deactivate(ComponentContext ctxt) { - JsFunctionRegistry jsFunctionRegistry = IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry(); - jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "OBAuthenticationWorker", - null); + if (IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry() != null) { + JsFunctionRegistry jsFunctionRegistry = IdentityExtensionsDataHolder.getInstance().getJsFunctionRegistry(); + jsFunctionRegistry.register(JsFunctionRegistry.Subsystem.SEQUENCE_HANDLER, "OBAuthenticationWorker", + null); + } log.debug("Open banking Key Manager Extensions component is deactivated"); } @Reference( service = JsFunctionRegistry.class, - cardinality = ReferenceCardinality.MANDATORY, + cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, unbind = "unsetJsFunctionRegistry" ) diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/TokenFilter.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/TokenFilter.java index 608fcbeb..f744ad05 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/TokenFilter.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/TokenFilter.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -132,15 +132,15 @@ private ServletRequest appendTransportHeader(ServletRequest request, ServletResp if (request instanceof HttpServletRequest) { Object certAttribute = request.getAttribute(IdentityCommonConstants.JAVAX_SERVLET_REQUEST_CERTIFICATE); String x509Certificate = ((HttpServletRequest) request).getHeader(IdentityCommonUtil.getMTLSAuthHeader()); - if (certAttribute != null) { + if (new IdentityCommonHelper().isTransportCertAsHeaderEnabled() && x509Certificate != null) { + return request; + } else if (certAttribute != null) { RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request); X509Certificate certificate = IdentityCommonUtil.getCertificateFromAttribute(certAttribute); requestWrapper.setHeader(IdentityCommonUtil.getMTLSAuthHeader(), new IdentityCommonHelper().encodeCertificateContent(certificate)); return requestWrapper; - } else if (new IdentityCommonHelper().isTransportCertAsHeaderEnabled() && x509Certificate != null) { - return request; - } else { + } else { getDefaultTokenFilter().handleValidationFailure((HttpServletResponse) response, HttpServletResponse.SC_BAD_REQUEST, IdentityCommonConstants.OAUTH2_INVALID_REQUEST_MESSAGE, "Transport certificate not found in the request"); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidator.java new file mode 100644 index 00000000..d1f45971 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidator.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. + */ + +package com.wso2.openbanking.accelerator.identity.token.validators; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.CertificateUtils; +import com.wso2.openbanking.accelerator.identity.token.util.TokenFilterException; +import com.wso2.openbanking.accelerator.identity.util.IdentityCommonConstants; +import com.wso2.openbanking.accelerator.identity.util.IdentityCommonUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.security.cert.X509Certificate; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * MTLS Certificate Validator. + * Validates the expiry status of the certificate. + */ +public class MTLSCertificateValidator implements OBIdentityFilterValidator { + + private static final Log log = LogFactory.getLog(MTLSCertificateValidator.class); + private static final String CERT_EXPIRED_ERROR = "Certificate with the serial number %s issued by the CA %s is " + + "expired"; + + @Override + public void validate(ServletRequest request, String clientId) throws TokenFilterException, ServletException { + + HttpServletRequest servletRequest = (HttpServletRequest) request; + String mtlsCertificate = servletRequest.getHeader(IdentityCommonUtil.getMTLSAuthHeader()); + // MTLSEnforcementValidator validates the presence of the certificate. + if (mtlsCertificate != null) { + try { + X509Certificate x509Certificate = CertificateUtils.parseCertificate(mtlsCertificate); + + if (CertificateUtils.isExpired(x509Certificate)) { + log.error(String.format(CERT_EXPIRED_ERROR, x509Certificate.getSerialNumber(), + x509Certificate.getIssuerDN().toString())); + throw new TokenFilterException(HttpServletResponse.SC_UNAUTHORIZED, + "Invalid mutual TLS request. Client certificate is expired", + String.format(CERT_EXPIRED_ERROR, x509Certificate.getSerialNumber(), + x509Certificate.getIssuerDN().toString())); + } + log.debug("Client certificate expiry validation completed successfully"); + } catch (OpenBankingException e) { + log.error("Invalid mutual TLS request. Client certificate is invalid", e); + throw new TokenFilterException(HttpServletResponse.SC_UNAUTHORIZED, IdentityCommonConstants + .OAUTH2_INVALID_CLIENT_MESSAGE, e.getMessage()); + } + } + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/SignatureAlgorithmEnforcementValidator.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/SignatureAlgorithmEnforcementValidator.java index fae6735a..a7065b3b 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/SignatureAlgorithmEnforcementValidator.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/main/java/com/wso2/openbanking/accelerator/identity/token/validators/SignatureAlgorithmEnforcementValidator.java @@ -47,7 +47,8 @@ public void validate(ServletRequest request, String clientId) throws TokenFilter if (request instanceof HttpServletRequest) { String signedObject = request.getParameter(IdentityCommonConstants.OAUTH_JWT_ASSERTION); - if (StringUtils.isNotEmpty(signedObject)) { + if (StringUtils.isNotEmpty(signedObject) && + StringUtils.isNotEmpty(getRegisteredSigningAlgorithm(clientId))) { validateInboundSignatureAlgorithm(getRequestSigningAlgorithm(signedObject), getRegisteredSigningAlgorithm(clientId)); } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthUtilsTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthUtilsTest.java new file mode 100644 index 00000000..f3b1b2dd --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthUtilsTest.java @@ -0,0 +1,194 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.identity.app2app.utils.App2AppAuthUtils; +import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.testng.Assert; +import org.testng.IObjectFactory; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerClientException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerServerException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.impl.DeviceHandlerImpl; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.model.Device; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test class for Unit Testing App2AppAuthUtils. + */ +@PrepareForTest({AuthenticatedUser.class, IdentityTenantUtil.class, IdentityExtensionsDataHolder.class}) +@PowerMockIgnore({"javax.net.ssl.*", "jdk.internal.reflect.*"}) +public class App2AppAuthUtilsTest { + + @Test + public void testGetAuthenticatedUserFromSubjectIdentifier() { + + PowerMockito.mockStatic(AuthenticatedUser.class); + // Prepare test data + String subjectIdentifier = "admin@wso2.com"; + // Mock the AuthenticatedUser class + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + // Mock the behavior of AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier() + Mockito.when(AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier(subjectIdentifier)) + .thenReturn(authenticatedUserMock); + // Call the method under test + AuthenticatedUser user = App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(subjectIdentifier); + // Verify the result + Assert.assertNotNull(user, "Authenticated user should not be null"); + Assert.assertEquals(user, authenticatedUserMock, "Returned user should match the mocked user"); + } + + @Test + public void testGetUserRealm() throws UserStoreException { + + // Mock the AuthenticatedUser + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + Mockito.when(authenticatedUserMock.getTenantDomain()).thenReturn("testTenantDomain"); + // Mock IdentityTenantUtil + PowerMockito.mockStatic(IdentityTenantUtil.class); + Mockito.when(IdentityTenantUtil.getTenantId(Mockito.anyString())).thenReturn(1234); + // Mock RealmService and UserRealm + RealmService realmServiceMock = Mockito.mock(RealmService.class); + UserRealm userRealmMock = Mockito.mock(UserRealm.class); + Mockito.when(realmServiceMock.getTenantUserRealm(1234)).thenReturn(userRealmMock); + // Mock IdentityExtensionsDataHolder + IdentityExtensionsDataHolder dataHolderMock = Mockito.mock(IdentityExtensionsDataHolder.class); + Mockito.when(dataHolderMock.getRealmService()).thenReturn(realmServiceMock); + PowerMockito.mockStatic(IdentityExtensionsDataHolder.class); + Mockito.when(IdentityExtensionsDataHolder.getInstance()).thenReturn(dataHolderMock); + // Call the method under test + UserRealm userRealm = App2AppAuthUtils.getUserRealm(authenticatedUserMock); + // Verify the result + Assert.assertEquals(userRealm, userRealmMock, "UserRealm should match the mocked UserRealm"); + } + + @Test + public void testGetUserRealmWhenUserIsNull() throws UserStoreException { + + // Call the method under test + UserRealm userRealm = App2AppAuthUtils.getUserRealm(null); + // Verify the result + Assert.assertNull(userRealm, "UserRealm should be null when the input is null."); + } + + @Test + public void testGetUserIdFromUsername() throws UserStoreException, OpenBankingException { + + // Prepare test data + String username = "admin@wso2.com"; + String userIDMock = "354cd9f4-ae85-4ce9-8c42-dc1111ac8acf"; + // Mock the UserRealm + UserRealm userRealmMock = Mockito.mock(UserRealm.class); + // Mock the AbstractUserStoreManager + AbstractUserStoreManager userStoreManagerMock = Mockito.mock(AbstractUserStoreManager.class); + Mockito.when(userStoreManagerMock.getUserIDFromUserName(username)).thenReturn(userIDMock); + // Mock the RealmService + Mockito.when(userRealmMock.getUserStoreManager()).thenReturn(userStoreManagerMock); + // Call the method under test + String userId = App2AppAuthUtils.getUserIdFromUsername(username, userRealmMock); + // Verify the result + Assert.assertNotNull(userId, "User ID should not be null"); + Assert.assertEquals(userId, userIDMock , + "User ID should match the expected value"); + } + + @Test(expectedExceptions = OpenBankingException.class) + public void testGetUserIdFromUsernameWhenRealmNull() throws UserStoreException, OpenBankingException { + + // Prepare test data + String username = "admin@wso2.com"; + // Mock the UserRealm + UserRealm userRealmMock = null; + // Call the method under test + String userId = App2AppAuthUtils.getUserIdFromUsername(username, userRealmMock); + } + + @Test + public void testGetPublicKey() throws PushDeviceHandlerServerException, PushDeviceHandlerClientException, + OpenBankingException { + + // Prepare test data + String deviceID = "testDeviceID"; + String invalidDeviceId = "invalidDeviceID"; + String userID = "testUserID"; + String publicKey = "testPublicKey"; + // Mock DeviceHandlerImpl and Device + DeviceHandlerImpl deviceHandlerMock = Mockito.mock(DeviceHandlerImpl.class); + Device deviceMockI = Mockito.mock(Device.class); + Device deviceMockII = Mockito.mock(Device.class); + Mockito.when(deviceMockI.getPublicKey()).thenReturn(publicKey); + Mockito.when(deviceMockI.getDeviceId()).thenReturn(deviceID); + Mockito.when(deviceMockII.getPublicKey()).thenReturn(publicKey); + Mockito.when(deviceMockII.getDeviceId()).thenReturn(invalidDeviceId); + // Mock DeviceHandlerImpl.listDevices() to return a list with the mock device + List deviceList = new ArrayList<>(); + deviceList.add(deviceMockI); + deviceList.add(deviceMockII); + Mockito.when(deviceHandlerMock.listDevices(userID)).thenReturn(deviceList); + Mockito.when(deviceHandlerMock.getPublicKey(deviceID)).thenReturn(publicKey); + // Call the method under test + String result = App2AppAuthUtils.getPublicKey(deviceID, userID, deviceHandlerMock); + // Verify the result + Assert.assertEquals(result, publicKey, "Public key should match"); + } + + @Test(expectedExceptions = OpenBankingException.class) + public void testGetPublicKeyInvalidDeviceID() throws PushDeviceHandlerServerException, + PushDeviceHandlerClientException, OpenBankingException { + + // Prepare test data + String deviceID = "testDeviceID"; + String invalidDeviceId = "invalidDeviceID"; + String userID = "testUserID"; + String publicKey = "testPublicKey"; + // Mock DeviceHandlerImpl and Device + DeviceHandlerImpl deviceHandlerMock = Mockito.mock(DeviceHandlerImpl.class); + Device deviceMock = Mockito.mock(Device.class); + Mockito.when(deviceMock.getPublicKey()).thenReturn(publicKey); + Mockito.when(deviceMock.getDeviceId()).thenReturn(invalidDeviceId); + // Mock DeviceHandlerImpl.listDevices() to return a list with the mock device + List deviceList = new ArrayList<>(); + deviceList.add(deviceMock); + Mockito.when(deviceHandlerMock.listDevices(userID)).thenReturn(deviceList); + Mockito.when(deviceHandlerMock.getPublicKey(userID)).thenReturn(publicKey); + // Call the method under test + String result = App2AppAuthUtils.getPublicKey(deviceID, userID, deviceHandlerMock); + } + + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthValidationTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthValidationTest.java new file mode 100644 index 00000000..36e24abd --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthValidationTest.java @@ -0,0 +1,179 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jwt.SignedJWT; +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.cache.JTICache; +import com.wso2.openbanking.accelerator.identity.app2app.exception.JWTValidationException; +import com.wso2.openbanking.accelerator.identity.app2app.model.DeviceVerificationToken; +import com.wso2.openbanking.accelerator.identity.app2app.testutils.App2AppUtilsTestJWTDataProvider; +import com.wso2.openbanking.accelerator.identity.app2app.utils.App2AppAuthUtils; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.testng.IObjectFactory; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.text.ParseException; +import java.util.Date; + +/** + * Test class for unit testing App2AppAuthValidations. + */ +@PrepareForTest({JTICache.class, JWTUtils.class}) +@PowerMockIgnore({"javax.net.ssl.*", "jdk.internal.reflect.*"}) +public class App2AppAuthValidationTest { + + @Test(dataProviderClass = App2AppUtilsTestJWTDataProvider.class, + dataProvider = "ValidJWTProvider") + public void validationTest(String jwtString, String publicKey, String requestObject) throws ParseException, + OpenBankingException, JOSEException, NoSuchAlgorithmException, InvalidKeySpecException { + + //Mocking JTICache and JWTUtils + PowerMockito.mockStatic(JTICache.class); + PowerMockito.mockStatic(JWTUtils.class); + Mockito.when(JTICache.getJtiDataFromCache(Mockito.anyString())).thenReturn(null); + Mockito.when(JWTUtils.isValidSignature(Mockito.any(SignedJWT.class), Mockito.anyString())) + .thenReturn(true); + Mockito.when(JWTUtils.isValidExpiryTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + Mockito.when(JWTUtils.isValidNotValidBeforeTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + //Creating a new device verification token using signed jwt + SignedJWT signedJWT = SignedJWT.parse(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(requestObject); + // Call the method under test + App2AppAuthUtils.validateToken(deviceVerificationToken); + } + + @Test(expectedExceptions = JWTValidationException.class, + dataProviderClass = App2AppUtilsTestJWTDataProvider.class, + dataProvider = "ValidJWTProvider") + public void validationTestJTIReplayed(String jwtString, String publicKey, String requestObject) throws + ParseException, OpenBankingException, JOSEException, NoSuchAlgorithmException, InvalidKeySpecException { + + //Mocking JTICache and JWTUtils + PowerMockito.mockStatic(JTICache.class); + PowerMockito.mockStatic(JWTUtils.class); + Mockito.when(JTICache.getJtiDataFromCache(Mockito.anyString())).thenReturn("NotNullJTI"); + Mockito.when(JWTUtils.isValidSignature(Mockito.any(SignedJWT.class), Mockito.anyString())) + .thenReturn(true); + Mockito.when(JWTUtils.isValidExpiryTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + Mockito.when(JWTUtils.isValidNotValidBeforeTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + //Creating a new device verification token using signed jwt + SignedJWT signedJWT = SignedJWT.parse(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(requestObject); + // Call the method under test + App2AppAuthUtils.validateToken(deviceVerificationToken); + } + + @Test(expectedExceptions = JWTValidationException.class, + dataProviderClass = App2AppUtilsTestJWTDataProvider.class, + dataProvider = "ValidJWTProvider") + public void validationTestJWTExpired(String jwtString, String publicKey, String requestObject) throws + ParseException, OpenBankingException, JOSEException, NoSuchAlgorithmException, InvalidKeySpecException { + + //Mocking JTICache and JWTUtils + PowerMockito.mockStatic(JTICache.class); + PowerMockito.mockStatic(JWTUtils.class); + Mockito.when(JTICache.getJtiDataFromCache(Mockito.anyString())).thenReturn(null); + Mockito.when(JWTUtils.isValidSignature(Mockito.any(SignedJWT.class), Mockito.anyString())) + .thenReturn(true); + Mockito.when(JWTUtils.isValidExpiryTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(false); + Mockito.when(JWTUtils.isValidNotValidBeforeTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + //Creating a new device verification token using signed jwt + SignedJWT signedJWT = SignedJWT.parse(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(requestObject); + // Call the method under test + App2AppAuthUtils.validateToken(deviceVerificationToken); + } + + @Test(expectedExceptions = JWTValidationException.class, + dataProviderClass = App2AppUtilsTestJWTDataProvider.class, + dataProvider = "ValidJWTProvider") + public void validationTestJWTNotActive(String jwtString, String publicKey, String requestObject) throws + ParseException, OpenBankingException, JOSEException, NoSuchAlgorithmException, InvalidKeySpecException { + + //Mocking JTICache and JWTUtils + PowerMockito.mockStatic(JTICache.class); + PowerMockito.mockStatic(JWTUtils.class); + Mockito.when(JTICache.getJtiDataFromCache(Mockito.anyString())).thenReturn(null); + Mockito.when(JWTUtils.isValidSignature(Mockito.any(SignedJWT.class), Mockito.anyString())). + thenReturn(true); + Mockito.when(JWTUtils.isValidExpiryTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + Mockito.when(JWTUtils.isValidNotValidBeforeTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(false); + //Creating a new device verification token using signed jwt + SignedJWT signedJWT = SignedJWT.parse(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(requestObject); + // Call the method under test + App2AppAuthUtils.validateToken(deviceVerificationToken); + } + + @Test(expectedExceptions = JWTValidationException.class, + dataProviderClass = App2AppUtilsTestJWTDataProvider.class, + dataProvider = "invalidDigestProvider") + public void validationTestInvalidDigest(String jwtString, String publicKey, String requestObject) throws + ParseException, OpenBankingException, JOSEException, NoSuchAlgorithmException, InvalidKeySpecException { + + //Mocking JTICache and JWTUtils + PowerMockito.mockStatic(JTICache.class); + PowerMockito.mockStatic(JWTUtils.class); + Mockito.when(JTICache.getJtiDataFromCache(Mockito.anyString())).thenReturn(null); + Mockito.when(JWTUtils.isValidSignature(Mockito.any(SignedJWT.class), Mockito.anyString())). + thenReturn(true); + Mockito.when(JWTUtils.isValidExpiryTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + Mockito.when(JWTUtils.isValidNotValidBeforeTime(Mockito.any(Date.class), Mockito.any(long.class))) + .thenReturn(true); + //Creating a new device verification token using signed jwt + SignedJWT signedJWT = SignedJWT.parse(jwtString); + DeviceVerificationToken deviceVerificationToken = new DeviceVerificationToken(signedJWT); + deviceVerificationToken.setPublicKey(publicKey); + deviceVerificationToken.setRequestObject(requestObject); + // Call the method under test + App2AppAuthUtils.validateToken(deviceVerificationToken); + } + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorTest.java new file mode 100644 index 00000000..812b4e08 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/App2AppAuthenticatorTest.java @@ -0,0 +1,281 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.app2app.testutils.App2AppAuthenticatorTestDataProvider; +import com.wso2.openbanking.accelerator.identity.app2app.utils.App2AppAuthUtils; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.testng.Assert; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; +import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerClientException; +import org.wso2.carbon.identity.application.authenticator.push.device.handler.exception.PushDeviceHandlerServerException; +import org.wso2.carbon.user.api.UserStoreException; + +import java.text.ParseException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.testng.Assert.assertEquals; + +/** + * Test class for unit testing App2AppAuthenticator. + */ +@PrepareForTest({App2AppAuthUtils.class, JWTUtils.class}) +@PowerMockIgnore({"javax.net.ssl.*", "jdk.internal.reflect.*"}) +public class App2AppAuthenticatorTest { + + private HttpServletRequest mockRequest; + private HttpServletResponse mockResponse; + + private AuthenticationContext mockAuthenticationContext; + private App2AppAuthenticator app2AppAuthenticator; + + @BeforeTest + public void setup() { + + // setting the authenticator for testing + app2AppAuthenticator = new App2AppAuthenticator(); + //Mocking the behaviour of request, response and authenticationContext + mockRequest = Mockito.mock(HttpServletRequest.class); + mockResponse = Mockito.mock(HttpServletResponse.class); + mockAuthenticationContext = Mockito.mock(AuthenticationContext.class); + } + + @Test + public void testGetName() { + + String expectedName = App2AppAuthenticatorConstants.AUTHENTICATOR_NAME; + String actualName = app2AppAuthenticator.getName(); + // Invoke the method under test + assertEquals(actualName, expectedName, "Expected and actual names should match."); + } + + @Test + public void testGetFriendlyName() { + + String expectedFriendlyName = App2AppAuthenticatorConstants.AUTHENTICATOR_FRIENDLY_NAME; + String actualFriendlyName = app2AppAuthenticator.getFriendlyName(); + // Invoke the method under test + assertEquals(actualFriendlyName, expectedFriendlyName, + "Expected and actual friendly names should match"); + } + + @Test(dataProviderClass = App2AppAuthenticatorTestDataProvider.class , + dataProvider = "app_auth_identifier_provider") + public void canHandleTestCase(String secret, String expected) { + + // Set up mock behavior for HttpServletRequest + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(secret); + // Invoke the method under test + assertEquals(Boolean.valueOf(expected).booleanValue(), app2AppAuthenticator.canHandle(mockRequest), + "Invalid can handle response for the request."); + } + + @Test(expectedExceptions = AuthenticationFailedException.class) + public void initiateAuthenticationRequest() throws AuthenticationFailedException { + + // Invoke the method under test + app2AppAuthenticator.initiateAuthenticationRequest(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "sessionDataKeyProvider") + public void getContextIdentifierTest(String sessionDataKey) { + + // Set up mock behavior for HttpServletRequest + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.SESSION_DATA_KEY)) + .thenReturn(sessionDataKey); + // Invoke the method under test + String output = app2AppAuthenticator.getContextIdentifier(mockRequest); + assertEquals(sessionDataKey, output); + } + + @Test(dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider") + public void testProcessAuthenticationResponse_success(String jwtString) { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Set up mock behavior for HttpServletRequest + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock the authenticated user + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + // Mock the behavior of App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier() to return a mocked user + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenReturn(authenticatedUserMock); + + try { + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + // Verify that the authentication context subject is set (or any other verification) + Mockito.verify(mockAuthenticationContext).setSubject(authenticatedUserMock); + } catch (Exception e) { + // If any unexpected exception occurs, fail the test + Assert.fail("Unexpected exception occurred: " + e.getMessage()); + } + } + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_IllegalArgumentException(String jwtString) + throws AuthenticationFailedException { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier to throw IllegalArgumentException + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenThrow(new IllegalArgumentException("Failed to create Local Authenticated User from the given " + + "subject identifier. Invalid argument. authenticatedSubjectIdentifier : ")); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_ParseException(String jwtString) + throws AuthenticationFailedException, ParseException { + + PowerMockito.mockStatic(JWTUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier to throw IllegalArgumentException + Mockito.when(JWTUtils.getSignedJWT(Mockito.anyString())) + .thenThrow(new ParseException("JWT Not parsable.", 1)); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_UserStoreException(String jwtString) + throws AuthenticationFailedException, UserStoreException { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock the behavior of App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier() to return a mock user + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenReturn(authenticatedUserMock); + // Mock the behavior of getPublicKeyByDeviceID() to throw UserStoreException + Mockito.when(App2AppAuthUtils.getUserRealm(Mockito.any(AuthenticatedUser.class))) + .thenThrow(new UserStoreException(App2AppAuthenticatorConstants.USER_STORE_EXCEPTION_MESSAGE)); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_PushDeviceHandlerServerException(String jwtString) + throws AuthenticationFailedException, OpenBankingException, PushDeviceHandlerServerException, + PushDeviceHandlerClientException { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock the behavior of App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier() to return a mock user + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenReturn(authenticatedUserMock); + // Mock the behavior of getPublicKeyByDeviceID() to throw UserStoreException + Mockito.when(App2AppAuthUtils.getPublicKey(Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenThrow(new PushDeviceHandlerServerException( + App2AppAuthenticatorConstants.PUSH_DEVICE_HANDLER_SERVER_EXCEPTION_MESSAGE)); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_PushDeviceHandlerClientException(String jwtString) + throws AuthenticationFailedException, OpenBankingException, PushDeviceHandlerServerException, + PushDeviceHandlerClientException { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock the behavior of App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier() to return a mock user + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenReturn(authenticatedUserMock); + // Mock the behavior of getPublicKeyByDeviceID() to throw UserStoreException + Mockito.when(App2AppAuthUtils.getPublicKey(Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenThrow(new PushDeviceHandlerClientException( + App2AppAuthenticatorConstants.PUSH_DEVICE_HANDLER_CLIENT_EXCEPTION_MESSAGE)); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + + @Test(expectedExceptions = AuthenticationFailedException.class, + dataProviderClass = App2AppAuthenticatorTestDataProvider.class, + dataProvider = "AppAuthIdentifierProvider" + ) + public void testProcessAuthenticationResponse_OpenBankingException(String jwtString) + throws AuthenticationFailedException, OpenBankingException, PushDeviceHandlerServerException, + PushDeviceHandlerClientException { + + PowerMockito.mockStatic(App2AppAuthUtils.class); + // Mock the behavior of HttpServletRequest to return a value for login hint + Mockito.when(mockRequest.getParameter(App2AppAuthenticatorConstants.DEVICE_VERIFICATION_TOKEN_IDENTIFIER)) + .thenReturn(jwtString); + // Mock the behavior of App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier() to return a mock user + AuthenticatedUser authenticatedUserMock = Mockito.mock(AuthenticatedUser.class); + Mockito.when(App2AppAuthUtils.getAuthenticatedUserFromSubjectIdentifier(Mockito.anyString())) + .thenReturn(authenticatedUserMock); + // Mock the behavior of getPublicKeyByDeviceID() to throw UserStoreException + Mockito.when(App2AppAuthUtils.getPublicKey(Mockito.anyString(), Mockito.anyString(), Mockito.any())) + .thenThrow(new OpenBankingException( + App2AppAuthenticatorConstants.OPEN_BANKING_EXCEPTION_MESSAGE)); + // Invoke the method under test + app2AppAuthenticator.processAuthenticationResponse(mockRequest, mockResponse, mockAuthenticationContext); + } + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppAuthenticatorTestDataProvider.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppAuthenticatorTestDataProvider.java new file mode 100644 index 00000000..ac39da2e --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppAuthenticatorTestDataProvider.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 com.wso2.openbanking.accelerator.identity.app2app.testutils; + +import org.testng.annotations.DataProvider; + +/** + * Data Provider class for testing App2AppAuthenticator. + */ +public class App2AppAuthenticatorTestDataProvider { + private static final String validAppAuthIdentifier = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ3LTRlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb" + + "2dpbl9oaW50IjoiYWRtaW5Ad3NvMi5jb20iLCJpYXQiOjE3MTYyNjQ5NTUsImp0aSI6IjA1NDU1Zjc1LTkwMmUtNDFhNi04ZDg4LWV" + + "jZTUwZDM2OTc2NSIsImRpZ2VzdCI6IlNIQS0yNTY9RWtIOGZQZ1oyVFkyWEduczhjNVZ2Y2U4aDNEQjgzVit3NDd6SGl5WWZpUT0iL" + + "CJleHAiOjE3MTYyNjY3NTUsIm5iZiI6MTcxNjI2NDk1NX0.C0OGMkkaosP2FSLFtqmCgRhrCG7nCJCDLsikkbFWwc5NdzxCFyYUQVI" + + "Zx4HIRQdabg5K8Ox-WYeqwdhajaKs5Uk63tz5UjlPzX0IKsklXgnWUxdMwfrYsu-znTce0Tc-Ph0h8a8jXF2CKTOfWxwuQvgevSqJe" + + "-K6zrbJmO8imu4"; + @DataProvider(name = "app_auth_identifier_provider") + public Object[][] getAppAuthIdentifier() { + + return new String[][]{ + {validAppAuthIdentifier, "true"}, + {null, "false"}, + {"", "false"}, + }; + } + + @DataProvider(name = "sessionDataKeyProvider") + public Object[][] getSessionDataKey() { + + return new String[][]{ + {null}, + {""}, + {"550e8400-e29b-41d4-a716-446655440000"}, + {"aaaaaaa-bbbb-Cccc-dddd-eeeeeeeeeeeee"} + }; + } + + @DataProvider(name = "AppAuthIdentifierProvider") + public Object[][] getJWT() { + return new String[][]{ + {validAppAuthIdentifier}, + }; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppUtilsTestJWTDataProvider.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppUtilsTestJWTDataProvider.java new file mode 100644 index 00000000..ffbc0f39 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/app2app/testutils/App2AppUtilsTestJWTDataProvider.java @@ -0,0 +1,83 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.app2app.testutils; + +import org.testng.annotations.DataProvider; + +/** + * JWT Data provider for App2AppAuthValidation Testing. + */ +public class App2AppUtilsTestJWTDataProvider { + + private final String validPublicKey = + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLyl7YvRhy57IbxuhV4n7OZw0mmnnXNsDJmL4YQNXy2bRCs59pJb+TYO" + + "HsR1xCsq3WH7bX1Ik/EI3weQd2zcxNbtDAUSXSy7jRBuFm1Sk52lASBbmdeOstiqlsg9ptIp/o7u1366cRjn32cXhhsR0y" + + "/spUGy8IiXz9rJfP5bEgHQIDAQ"; + private final String validAppAuthIdentifier = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ3LTRlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb" + + "2dpbl9oaW50IjoiYWRtaW5Ad3NvMi5jb20iLCJpYXQiOjE3MTYyNjQ5NTUsImp0aSI6IjA1NDU1Zjc1LTkwMmUtNDFhNi04ZDg4LWV" + + "jZTUwZDM2OTc2NSIsImRpZ2VzdCI6IlNIQS0yNTY9RWtIOGZQZ1oyVFkyWEduczhjNVZ2Y2U4aDNEQjgzVit3NDd6SGl5WWZpUT0iL" + + "CJleHAiOjE3MTYyNjY3NTUsIm5iZiI6MTcxNjI2NDk1NX0.C0OGMkkaosP2FSLFtqmCgRhrCG7nCJCDLsikkbFWwc5NdzxCFyYUQVI" + + "Zx4HIRQdabg5K8Ox-WYeqwdhajaKs5Uk63tz5UjlPzX0IKsklXgnWUxdMwfrYsu-znTce0Tc-Ph0h8a8jXF2CKTOfWxwuQvgevSqJe" + + "-K6zrbJmO8imu4"; + private final String appAuthIdentifierMissingDigest = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ3LTRlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb" + + "2dpbl9oaW50IjoiYWRtaW5Ad3NvMi5jb20iLCJpYXQiOjE3MTYyNjcyMDMsImp0aSI6ImZkNDhmOWMzLTYyZDMtNDUzZS04MWY2LTF" + + "kMGE4ZDIzM2YzZiIsImV4cCI6MTcxNjI2OTAwMywibmJmIjoxNzE2MjY3MjAzfQ.C_G5-_McCMTz6D01XpPVfrdGlPLaKli9cqWL5K" + + "nd5ntlDq5ww7J769EJdCGt-S5sfgg5hrPRhyIWK2MJwavGTMzsp1vGdUQXQkT7z68_20k82Lms67tQLIM1VUCDc9rqz5Pule5bVqbY" + + "oZFmFlHU0Hcmvy166J6c9HlySyMC994"; + private final String appAuthIdentifierInvalidDigest = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiOiI1NTBmNDQ1My05NTQ3LTRlNGYtYmUwNi04ZGIyZWVkNTYzYjMiLCJsb" + + "2dpbl9oaW50IjoiYWRtaW5Ad3NvMi5jb20iLCJpYXQiOjE3MTYyNjc0MjYsImp0aSI6IjYyM2ZhZDY3LTc0ZDMtNDk4OS04YTc1LTE" + + "2OWYxNDQzOGUwZiIsImRpZ2VzdCI6IlNIQS0yNTY9WUJlc3lUWnhIMWtBVitMTTNKMzZDdzQrVXlQYWlKS0VydVhsdGxsbS9DRT0iL" + + "CJleHAiOjE3MTYyNjkyMjYsIm5iZiI6MTcxNjI2NzQyNn0.hsuj0osE-o_hyOif7eUvVFIfJpmzF2bDqeINj2Qq2XMQ1Lbnf7LgYMG" + + "POzmtMi1Jp9Ivwl_3Wt35PcCVko2LI2TIoG-JB8MMeWc1okwwdWGP8Rz5TWCnaXiPGeeFw4PjuV3JMbWeTFafqUFtJUX7pU-8q_hiQ" + + "zxK1mGjRTjDXRA"; + private final String validRequestObject = + "eyJraWQiOiI3ZUo4U19aZ3ZsWXhGQUZTZ2hWOXhNSlJPdmsiLCJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJtYXhfYWdlIjo4N" + + "jQwMCwiYXVkIjoiaHR0cHM6Ly8xOTIuMTY4LjQzLjQ5Ojk0NDYvb2F1dGgyL3Rva2VuIiwic2NvcGUiOiJhY2NvdW50cyBvcGVuaWQ" + + "iLCJpc3MiOiI2RWZaSTVOUnByTm9tZlFQWElQZjFSN0ZsNUVhIiwiY2xhaW1zIjp7ImlkX3Rva2VuIjp7ImFjciI6eyJ2YWx1ZXMiO" + + "lsidXJuOm9wZW5iYW5raW5nOnBzZDI6c2NhIiwidXJuOm9wZW5iYW5raW5nOnBzZDI6Y2EiXSwiZXNzZW50aWFsIjp0cnVlfSwib3B" + + "lbmJhbmtpbmdfaW50ZW50X2lkIjp7InZhbHVlIjoiZTkyNmE2MzItYzlkMy00MmEwLWEyM2YtMWEwMWZhNDAwOWU3IiwiZXNzZW50a" + + "WFsIjp0cnVlfX0sInVzZXJpbmZvIjp7Im9wZW5iYW5raW5nX2ludGVudF9pZCI6eyJ2YWx1ZSI6ImU5MjZhNjMyLWM5ZDMtNDJhMC1" + + "hMjNmLTFhMDFmYTQwMDllNyIsImVzc2VudGlhbCI6dHJ1ZX19fSwicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLCJyZWRpc" + + "mVjdF91cmkiOiJodHRwczovL3d3dy5tb2NrY29tcGFueS5jb20vcmVkaXJlY3RzL3JlZGlyZWN0MSIsInN0YXRlIjoiWVdsemNEb3p" + + "NVFE0IiwiZXhwIjoxODA3MjMzNDc4LCJub25jZSI6Im4tMFM2X1d6QTJNbCIsImNsaWVudF9pZCI6IjZFZlpJNU5ScHJOb21mUVBYS" + + "VBmMVI3Rmw1RWEifQ.nKapNc1N5AHxil-xbVpSXrDRsGYkn1YHe1jURxZMVRluDWnyRmjVce9AJ5lCl338Jg0EsU4CNmLwOSu7zmtl" + + "DCFz4fCIHLj1Q8A-C5I9cWE-nAlV1HnCR_3V7cTU4YE13ZIH7bMCqOPfBX_fpDkJeDXoSnRHQtipMPqIwNfmv7Kf4SjPpZ7kT5zmDn" + + "cHsUqotpPVoPka_-Nal0KL_-PknC31pKECcxakOFNTeAeiODZN5JIyKGFtq10jQaJi7YvDKsGg1l3rv1gUdJ4s5eXqmnxJUu4J6ocY" + + "h26Nz3l_Xc1p7XIm2HPhvSW3DpbNpE8Ej0kJkI9FgWz77QACkiO4Hg"; + + @DataProvider(name = "ValidJWTProvider") + public Object[][] getDigest() { + return new String[][]{ + {validAppAuthIdentifier, validPublicKey, null}, + {validAppAuthIdentifier, validPublicKey, validRequestObject} + }; + } + + @DataProvider(name = "invalidDigestProvider") + public Object[][] getInvalidDigest() { + return new String[][]{ + {appAuthIdentifierMissingDigest, validPublicKey, validRequestObject}, + {appAuthIdentifierInvalidDigest, validPublicKey, validRequestObject} + }; + } +} + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/authz/request/OBOAuthAuthzRequestTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/authz/request/OBOAuthAuthzRequestTest.java index 1e3b475f..01864c22 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/authz/request/OBOAuthAuthzRequestTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/authz/request/OBOAuthAuthzRequestTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -34,6 +34,8 @@ import org.wso2.carbon.identity.oauth.common.CodeTokenResponseValidator; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -273,4 +275,54 @@ public void testValidGetStateFromRequestURI() throws OAuthProblemException, OAut assertEquals(obOAuthAuthzRequest.getState(), "abc"); } + @Test + public void testInvalidGetStateFromRequestURI() throws OAuthProblemException, OAuthSystemException { + + Map mockParameterMap = new HashMap<>(); + mockParameterMap.put(IdentityCommonConstants.RESPONSE_TYPE, new String[]{"code id_token"}); + mockParameterMap.put(IdentityCommonConstants.REQUEST_URI, + new String[]{SAMPLE_REQUEST_URI}); + + when(mockRequest.getParameterMap()).thenReturn(mockParameterMap); + when(mockRequest.getParameter(IdentityCommonConstants.RESPONSE_TYPE)).thenReturn("code id_token"); + when(mockRequest.getParameter(IdentityCommonConstants.REDIRECT_URI)).thenReturn("abc.com"); + when(mockRequest.getParameter(IdentityCommonConstants.SCOPE)).thenReturn("openid"); + when(mockRequest.getParameter(IdentityCommonConstants.REQUEST_URI)).thenReturn(SAMPLE_REQUEST_URI); + + // Simulate an exception being thrown when decoding the state + PowerMockito.when(IdentityCommonUtil.decodeRequestObjectAndGetKey(mockRequest, OAuth.OAUTH_STATE)) + .thenThrow(OAuthProblemException.error("invalid_request").description("Invalid state").state("abc")); + + obOAuthAuthzRequest = new OBOAuthAuthzRequest(mockRequest); + + assertEquals(obOAuthAuthzRequest.getState(), null); + } + + @Test + public void testValidGetScopesFromRequest_WhenRequestURIIsAbsent() throws OAuthProblemException, + OAuthSystemException { + + Map mockParameterMap = new HashMap<>(); + mockParameterMap.put(IdentityCommonConstants.RESPONSE_TYPE, new String[]{"code id_token"}); + mockParameterMap.put(IdentityCommonConstants.SCOPE, new String[]{"openid"}); + mockParameterMap.put(IdentityCommonConstants.REQUEST, + new String[]{Base64.getEncoder().encodeToString( + "{\"scope\": \"openid\", \"redirect_uri\": \"http://example.com\"}".getBytes( + StandardCharsets.UTF_8))}); + mockParameterMap.put(IdentityCommonConstants.REDIRECT_URI, new String[]{"http://example.com"}); + + when(mockRequest.getParameterMap()).thenReturn(mockParameterMap); + when(mockRequest.getParameter(IdentityCommonConstants.RESPONSE_TYPE)).thenReturn("code id_token"); + when(mockRequest.getParameter(IdentityCommonConstants.SCOPE)).thenReturn("openid"); + when(mockRequest.getParameter(IdentityCommonConstants.REQUEST)).thenReturn( + Base64.getEncoder().encodeToString( + "{\"scope\": \"openid\", \"redirect_uri\": \"http://example.com\"}".getBytes( + StandardCharsets.UTF_8))); + when(mockRequest.getParameter(IdentityCommonConstants.REDIRECT_URI)).thenReturn("http://example.com"); + + obOAuthAuthzRequest = new OBOAuthAuthzRequest(mockRequest); + + assertEquals(obOAuthAuthzRequest.getScopes(), new HashSet<>(Collections.singletonList("openid"))); + } + } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/response/handler/ResponseTypeHandlerTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/response/handler/ResponseTypeHandlerTest.java index 0d7f65c7..a6df365f 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/response/handler/ResponseTypeHandlerTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/auth/extensions/response/handler/ResponseTypeHandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -28,10 +28,12 @@ import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.fail; import static org.testng.AssertJUnit.assertEquals; /** @@ -96,7 +98,7 @@ public void checkValidCodeResponseTypeHandling() throws IdentityOAuth2Exception, } @Test - public void checkHandlerLogic() { + public void checkHandlerLogic() { OAuthAuthzReqMessageContext mock = mock(OAuthAuthzReqMessageContext.class); when(mock.getRefreshTokenvalidityPeriod()).thenReturn(6666L); @@ -107,4 +109,24 @@ public void checkHandlerLogic() { assertEquals(6666L, uut.updateRefreshTokenValidityPeriod(mock)); } + + @Test + public void checkExceptionHandling_WhenIsRegulatoryThrowsOpenBankingException() throws Exception { + + OAuthAuthzReqMessageContext mockAuthzReqMsgCtx = mock(OAuthAuthzReqMessageContext.class); + OAuth2AuthorizeReqDTO mockAuthorizeReqDTO = mock(OAuth2AuthorizeReqDTO.class); + when(mockAuthzReqMsgCtx.getAuthorizationReqDTO()).thenReturn(mockAuthorizeReqDTO); + when(mockAuthorizeReqDTO.getConsumerKey()).thenReturn("dummyClientId"); + OBCodeResponseTypeHandlerExtension uut = spy(new OBCodeResponseTypeHandlerExtension()); + doThrow(new OpenBankingException("Simulated isRegulatory exception")) + .when(uut).isRegulatory("dummyClientId"); + + try { + uut.issue(mockAuthzReqMsgCtx); + fail("Expected IdentityOAuth2Exception was not thrown."); + } catch (IdentityOAuth2Exception e) { + // Verify that the IdentityOAuth2Exception is thrown with the expected message + assertEquals("Error while reading regulatory property", e.getMessage()); + } + } } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/claims/OBDefaultOIDCClaimsCallbackHandlerTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/claims/OBDefaultOIDCClaimsCallbackHandlerTest.java index 125666d7..8b0e3466 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/claims/OBDefaultOIDCClaimsCallbackHandlerTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/claims/OBDefaultOIDCClaimsCallbackHandlerTest.java @@ -139,7 +139,7 @@ public void testHandleCustomClaims() throws OpenBankingException, IdentityOAuth2 assertEquals("123", jwtClaimsSet.getClaim("consent_id")); - assertEquals("{x5t#S256=GA370hkNKyI1C060VmxL4xZtKyjD6aQUjrGKYWoeZX8}", jwtClaimsSet.getClaim( + assertEquals("{x5t#S256=807-E8KgUMV6dRHTQi1_QYo5eyPvjmjbxCtunbFixV0}", jwtClaimsSet.getClaim( "cnf").toString()); assertEquals("aaa@gold.com", jwtClaimsSet.getClaim("sub")); } diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/util/ExtendedRegistrationRequest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/util/ExtendedRegistrationRequest.java index e70066e1..db22db7d 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/util/ExtendedRegistrationRequest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/util/ExtendedRegistrationRequest.java @@ -17,10 +17,10 @@ */ package com.wso2.openbanking.accelerator.identity.dcr.util; +import com.wso2.openbanking.accelerator.identity.common.annotations.validationgroups.MandatoryChecks; import com.wso2.openbanking.accelerator.identity.dcr.model.RegistrationRequest; import com.wso2.openbanking.accelerator.identity.dcr.model.SoftwareStatementBody; import com.wso2.openbanking.accelerator.identity.dcr.validation.DCRCommonConstants; -import com.wso2.openbanking.accelerator.identity.dcr.validation.validationgroups.MandatoryChecks; import java.util.List; diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/AlgorithmValidatorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/AlgorithmValidatorTest.java new file mode 100644 index 00000000..3e474e73 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/AlgorithmValidatorTest.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 com.wso2.openbanking.accelerator.identity.dcr.validation; + +import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; +import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateAlgorithm; +import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; +import org.apache.commons.beanutils.BeanUtils; +import org.mockito.Mock; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.validation.ConstraintValidatorContext; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@PowerMockIgnore("jdk.internal.reflect.*") +@PrepareForTest({BeanUtils.class, IdentityExtensionsDataHolder.class}) +public class AlgorithmValidatorTest extends PowerMockTestCase { + + private AlgorithmValidator validator; + + @Mock + private ValidateAlgorithm validateAlgorithm; + + @BeforeMethod + public void setUp() { + validator = new AlgorithmValidator(); + + when(validateAlgorithm.idTokenAlg()).thenReturn("idTokenAlg"); + when(validateAlgorithm.reqObjAlg()).thenReturn("reqObjAlg"); + when(validateAlgorithm.tokenAuthAlg()).thenReturn("tokenAuthAlg"); + + validator.initialize(validateAlgorithm); + } + + @Test + public void testIsValid_ReturnsTrue_WhenAlgorithmsAreAllowed() throws Exception { + Object requestObject = mock(Object.class); + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + + PowerMockito.mockStatic(BeanUtils.class); + PowerMockito.when(BeanUtils.getProperty(requestObject, "idTokenAlg")).thenReturn("RS256"); + PowerMockito.when(BeanUtils.getProperty(requestObject, "reqObjAlg")).thenReturn("RS256"); + PowerMockito.when(BeanUtils.getProperty(requestObject, "tokenAuthAlg")).thenReturn("RS256"); + + List allowedAlgorithms = Arrays.asList("RS256", "HS256"); + + PowerMockito.mockStatic(IdentityExtensionsDataHolder.class); + IdentityExtensionsDataHolder dataHolder = PowerMockito.mock(IdentityExtensionsDataHolder.class); + Map configMap = new HashMap<>(); + configMap.put(OpenBankingConstants.SIGNATURE_ALGORITHMS, allowedAlgorithms); + when(dataHolder.getConfigurationMap()).thenReturn(configMap); + PowerMockito.when(IdentityExtensionsDataHolder.getInstance()).thenReturn(dataHolder); + + boolean result = validator.isValid(requestObject, context); + Assert.assertTrue(result); + } + + @Test + public void testIsValid_ReturnsFalse_WhenAlgorithmsAreNotAllowed() throws Exception { + Object requestObject = mock(Object.class); + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + + PowerMockito.mockStatic(BeanUtils.class); + PowerMockito.when(BeanUtils.getProperty(requestObject, "idTokenAlg")).thenReturn("RS512"); + PowerMockito.when(BeanUtils.getProperty(requestObject, "reqObjAlg")).thenReturn("RS512"); + PowerMockito.when(BeanUtils.getProperty(requestObject, "tokenAuthAlg")).thenReturn("RS512"); + + List allowedAlgorithms = Arrays.asList("RS256", "HS256"); + + PowerMockito.mockStatic(IdentityExtensionsDataHolder.class); + IdentityExtensionsDataHolder dataHolder = PowerMockito.mock(IdentityExtensionsDataHolder.class); + Map configMap = new HashMap<>(); + configMap.put(OpenBankingConstants.SIGNATURE_ALGORITHMS, allowedAlgorithms); + when(dataHolder.getConfigurationMap()).thenReturn(configMap); + PowerMockito.when(IdentityExtensionsDataHolder.getInstance()).thenReturn(dataHolder); + + boolean result = validator.isValid(requestObject, context); + Assert.assertFalse(result); + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidatorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidatorTest.java new file mode 100644 index 00000000..a5f30382 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/IssuerValidatorTest.java @@ -0,0 +1,81 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.dcr.validation; + +import com.wso2.openbanking.accelerator.common.util.JWTUtils; +import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateIssuer; +import org.apache.commons.beanutils.BeanUtils; +import org.mockito.Mock; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import javax.validation.ConstraintValidatorContext; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@PowerMockIgnore("jdk.internal.reflect.*") +@PrepareForTest({JWTUtils.class, BeanUtils.class}) +public class IssuerValidatorTest extends PowerMockTestCase { + + private IssuerValidator validator; + + @Mock + private ValidateIssuer validateIssuer; + + @BeforeMethod + public void setUp() { + validator = new IssuerValidator(); + + when(validateIssuer.issuerProperty()).thenReturn("issuer"); + when(validateIssuer.ssa()).thenReturn("ssa"); + + validator.initialize(validateIssuer); + } + + @Test + public void testIsValid_ReturnsTrue_WhenIssuerOrSoftwareStatementIsNull() throws Exception { + Object registrationRequest = mock(Object.class); + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + + PowerMockito.mockStatic(BeanUtils.class); + PowerMockito.when(BeanUtils.getProperty(registrationRequest, "issuer")).thenReturn(null); + PowerMockito.when(BeanUtils.getProperty(registrationRequest, "ssa")).thenReturn(null); + + boolean result = validator.isValid(registrationRequest, context); + Assert.assertTrue(result); + } + + @Test + public void testIsValid_ReturnsFalse_OnException() throws Exception { + Object registrationRequest = mock(Object.class); + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + + PowerMockito.mockStatic(BeanUtils.class); + PowerMockito.when(BeanUtils.getProperty(registrationRequest, "issuer")).thenThrow(new NoSuchMethodException()); + PowerMockito.when(BeanUtils.getProperty(registrationRequest, "ssa")).thenReturn("dummy-ssa"); + + boolean result = validator.isValid(registrationRequest, context); + Assert.assertFalse(result); + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidatorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidatorTest.java new file mode 100644 index 00000000..1c286cbf --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/dcr/validation/RequiredParamsValidatorTest.java @@ -0,0 +1,160 @@ +/** + * 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 com.wso2.openbanking.accelerator.identity.dcr.validation; + +import com.wso2.openbanking.accelerator.identity.dcr.model.RegistrationRequest; +import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateRequiredParams; +import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; +import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl; +import org.hibernate.validator.internal.engine.path.PathImpl; +import org.mockito.Mock; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.validation.ConstraintValidatorContext; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +@PowerMockIgnore("jdk.internal.reflect.*") +@PrepareForTest({IdentityExtensionsDataHolder.class}) +public class RequiredParamsValidatorTest extends PowerMockTestCase { + + private RequiredParamsValidator validator; + + @Mock + private ValidateRequiredParams validateRequiredParams; + + private IdentityExtensionsDataHolder identityExtensionsDataHolderMock; + + @BeforeMethod + public void setUp() { + validator = new RequiredParamsValidator(); + validator.initialize(validateRequiredParams); + + PowerMockito.mockStatic(IdentityExtensionsDataHolder.class); + identityExtensionsDataHolderMock = PowerMockito.mock(IdentityExtensionsDataHolder.class); + PowerMockito.when(IdentityExtensionsDataHolder.getInstance()).thenReturn(identityExtensionsDataHolderMock); + + // Mock the DCR registration config map with some test data + Map> configMap = new HashMap<>(); + Map paramConfig = new HashMap<>(); + paramConfig.put(DCRCommonConstants.DCR_REGISTRATION_PARAM_REQUIRED, "true"); + configMap.put("tokenEndPointAuthentication", paramConfig); + + Map scopeAllowedValuesConfig = new HashMap<>(); + scopeAllowedValuesConfig.put(DCRCommonConstants.DCR_REGISTRATION_PARAM_ALLOWED_VALUES, Arrays.asList( + "scope1", "scope2")); + configMap.put("scope", scopeAllowedValuesConfig); + + + Map appTypeAllowedValuesConfig = new HashMap<>(); + appTypeAllowedValuesConfig.put(DCRCommonConstants.DCR_REGISTRATION_PARAM_ALLOWED_VALUES, Arrays.asList( + "web", "mobile")); + configMap.put("applicationType", appTypeAllowedValuesConfig); + + PowerMockito.when(identityExtensionsDataHolderMock.getDcrRegistrationConfigMap()).thenReturn(configMap); + } + + @Test + public void testIsValid_ReturnsTrue_WhenAllRequestObjectIsEmpty() { + PowerMockito.when(identityExtensionsDataHolderMock.getDcrRegistrationConfigMap()).thenReturn(new HashMap<>()); + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + doReturn(getConstraintViolationBuilder()).when(context).buildConstraintViolationWithTemplate(anyString()); + RegistrationRequest request = new RegistrationRequest(); + boolean result = validator.isValid(request, context); + Assert.assertTrue(result); + } + + @Test + public void testIsValid_ReturnsTrue_WhenRequiredParametersArePresent() { + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + doReturn(getConstraintViolationBuilder()).when(context).buildConstraintViolationWithTemplate(anyString()); + RegistrationRequest request = getSampleRegistrationRequestWithRequiredParams(); + boolean result = validator.isValid(request, context); + Assert.assertTrue(result); + } + + @Test + public void testIsValid_ReturnsFalse_WhenRequiredParameterIsBlank() { + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + doReturn(getConstraintViolationBuilder()).when(context).buildConstraintViolationWithTemplate(anyString()); + RegistrationRequest request = getSampleRegistrationRequestWithBlankRequiredParams(); + boolean result = validator.isValid(request, context); + Assert.assertFalse(result); + } + + @Test + public void testIsValid_ReturnsFalse_WhenScopeNotAllowed() { + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + doReturn(getConstraintViolationBuilder()).when(context).buildConstraintViolationWithTemplate(anyString()); + RegistrationRequest request = getSampleRegistrationRequestWithScope(); + boolean result = validator.isValid(request, context); + Assert.assertFalse(result); + } + + private ConstraintValidatorContext.ConstraintViolationBuilder getConstraintViolationBuilder() { + + PathImpl propertyPath = PathImpl.createPathFromString("example.path"); + ConstraintValidatorContextImpl context = new ConstraintValidatorContextImpl( + null, + null, + propertyPath, + null, + null + ); + return context.buildConstraintViolationWithTemplate("message"); + } + + private RegistrationRequest getSampleRegistrationRequestWithRequiredParams() { + + RegistrationRequest registrationRequest = new RegistrationRequest(); + registrationRequest.setApplicationType("web"); + registrationRequest.setTokenEndPointAuthentication("auth_method"); + registrationRequest.setScope("scope1 scope2"); + return registrationRequest; + } + + private RegistrationRequest getSampleRegistrationRequestWithBlankRequiredParams() { + + RegistrationRequest registrationRequest = new RegistrationRequest(); + registrationRequest.setApplicationType("web"); + registrationRequest.setTokenEndPointAuthentication(""); + registrationRequest.setScope("scope1 scope2"); + return registrationRequest; + } + + private RegistrationRequest getSampleRegistrationRequestWithScope() { + + RegistrationRequest registrationRequest = new RegistrationRequest(); + registrationRequest.setTokenEndPointAuthentication("auth_method"); + registrationRequest.setScope("scope1 scope3"); + return registrationRequest; + } + +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/util/TestConstants.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/util/TestConstants.java index ce58aef0..971c2158 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/util/TestConstants.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/util/TestConstants.java @@ -24,7 +24,7 @@ public class TestConstants { public static final String TARGET_STREAM = "targetStream"; public static final String CERTIFICATE_HEADER = "x-wso2-mutual-auth-cert"; - public static final String CERTIFICATE_CONTENT = "-----BEGIN CERTIFICATE-----" + + public static final String EXPIRED_CERTIFICATE_CONTENT = "-----BEGIN CERTIFICATE-----" + "MIIFODCCBCCgAwIBAgIEWcWGxDANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJH" + "QjEUMBIGA1UEChMLT3BlbkJhbmtpbmcxLjAsBgNVBAMTJU9wZW5CYW5raW5nIFBy" + "ZS1Qcm9kdWN0aW9uIElzc3VpbmcgQ0EwHhcNMTkwNTE2MDg0NDQ2WhcNMjAwNjE2" + @@ -54,6 +54,37 @@ public class TestConstants { "wtXOy27LE4exJRuZsF1CA78ObaRytuE3DJcnIRdhOcjWieS/MxZD7bzuuAPu5ySX" + "i2/qxT3AlWtHtxrz0mKSC3rlgYAHCzCAHoASWKpf5tnB3TodPVZ6DYOu7oI=" + "-----END CERTIFICATE-----"; + + public static final String CERTIFICATE_CONTENT = "-----BEGIN CERTIFICATE-----\n" + + "MIIFODCCBCCgAwIBAgIEWcbiiTANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJH\n" + + "QjEUMBIGA1UEChMLT3BlbkJhbmtpbmcxLjAsBgNVBAMTJU9wZW5CYW5raW5nIFBy\n" + + "ZS1Qcm9kdWN0aW9uIElzc3VpbmcgQ0EwHhcNMjMxMTE1MDUxMDMxWhcNMjQxMjE1\n" + + "MDU0MDMxWjBhMQswCQYDVQQGEwJHQjEUMBIGA1UEChMLT3BlbkJhbmtpbmcxGzAZ\n" + + "BgNVBAsTEjAwMTU4MDAwMDFIUVFyWkFBWDEfMB0GA1UEAxMWakZRdVE0ZVFiTkNN\n" + + "U3FkQ29nMjFuRjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJslGjTm\n" + + "0tWwnnKgC7WNqUSYNxblURkJyoD5UuSmzpsM5nlUBAxYxBgztTo062LJELzUTzA/\n" + + "9kgLIMMgj+wG1OS475QCgeyoDmwf0SPuFRBl0G0AjxAvJzzs2aijzxiYRbKUa4gm\n" + + "O1KPU3Xlz89mi8lwjTZlxtGk3ABwBG4f5na5TY7uZMlgWPXDnTg7Cc1H4mrMbEFk\n" + + "UaXmb6ZhhGtp0JL04+4Lp16QWrgiHrlop+P8bd+pwmmOmLuglTIEh+v993j+7v8B\n" + + "XYqdmYQ3noiOhK9ynFPD1A7urrm71Pgkuq+Wk5HCvMiBK7zZ4Sn9FDovykDKZTFY\n" + + "MloVDXLhmfDQrmcCAwEAAaOCAgQwggIAMA4GA1UdDwEB/wQEAwIHgDAgBgNVHSUB\n" + + "Af8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgeAGA1UdIASB2DCB1TCB0gYLKwYB\n" + + "BAGodYEGAWQwgcIwKgYIKwYBBQUHAgEWHmh0dHA6Ly9vYi50cnVzdGlzLmNvbS9w\n" + + "b2xpY2llczCBkwYIKwYBBQUHAgIwgYYMgYNVc2Ugb2YgdGhpcyBDZXJ0aWZpY2F0\n" + + "ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNlIG9mIHRoZSBPcGVuQmFua2luZyBSb290\n" + + "IENBIENlcnRpZmljYXRpb24gUG9saWNpZXMgYW5kIENlcnRpZmljYXRlIFByYWN0\n" + + "aWNlIFN0YXRlbWVudDBtBggrBgEFBQcBAQRhMF8wJgYIKwYBBQUHMAGGGmh0dHA6\n" + + "Ly9vYi50cnVzdGlzLmNvbS9vY3NwMDUGCCsGAQUFBzAChilodHRwOi8vb2IudHJ1\n" + + "c3Rpcy5jb20vb2JfcHBfaXNzdWluZ2NhLmNydDA6BgNVHR8EMzAxMC+gLaArhilo\n" + + "dHRwOi8vb2IudHJ1c3Rpcy5jb20vb2JfcHBfaXNzdWluZ2NhLmNybDAfBgNVHSME\n" + + "GDAWgBRQc5HGIXLTd/T+ABIGgVx5eW4/UDAdBgNVHQ4EFgQU7T6cMtCSQTT5JWW3\n" + + "O6vifRUSdpkwDQYJKoZIhvcNAQELBQADggEBAE9jrd/AE65vy3SEWdmFKPS4su7u\n" + + "EHy+KH18PETV6jMF2UFIJAOx7jl+5a3O66NkcpxFPeyvSuH+6tAAr2ZjpoQwtW9t\n" + + "Z9k2KSOdNOiJeQgjavwQC6t/BHI3yXWOIQm445BUN1cV9pagcRJjRyL3SPdHVoRf\n" + + "IbF7VI/+ULHwWdZYPXxtwUoda1mQFf6a+2lO4ziUHb3U8iD90FBURzID7WJ1ODSe\n" + + "B5zE/hG9Sxd9wlSXvl1oNmc/ha5oG/7rJpRqrx5Dcq3LEoX9iZZ3knHLkCm/abIQ\n" + + "7Nff8GQytuGhnGZxmGFYKDXdKElcl9dAlZ3bIK2I+I6jD2z2XvSfrhFyRjU=\n" + + "-----END CERTIFICATE-----"; public static final String CLIENT_ASSERTION = "eyJraWQiOiJqeVJVY3l0MWtWQ2xjSXZsVWxjRHVrVlozdFUiLCJhbGciOiJQUzI1" + "NiJ9.eyJzdWIiOiJpWXBSbTY0YjJ2bXZtS0RoZEw2S1pEOXo2ZmNhIiwiYXVkIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6OTQ0My9vYXV0a" + "DIvdG9rZW4iLCJpc3MiOiJpWXBSbTY0YjJ2bXZtS0RoZEw2S1pEOXo2ZmNhIiwiZXhwIjoxNjEwNjMxNDEyLCJpYXQiOjE2MTA2MDE" + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidatorTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidatorTest.java new file mode 100644 index 00000000..b1ec9332 --- /dev/null +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/java/com/wso2/openbanking/accelerator/identity/token/validators/MTLSCertificateValidatorTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. + */ + +package com.wso2.openbanking.accelerator.identity.token.validators; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; +import com.wso2.openbanking.accelerator.identity.internal.IdentityExtensionsDataHolder; +import com.wso2.openbanking.accelerator.identity.token.DefaultTokenFilter; +import com.wso2.openbanking.accelerator.identity.token.TokenFilter; +import com.wso2.openbanking.accelerator.identity.token.util.TestConstants; +import com.wso2.openbanking.accelerator.identity.token.util.TestUtil; +import com.wso2.openbanking.accelerator.identity.util.IdentityCommonConstants; +import com.wso2.openbanking.accelerator.identity.util.IdentityCommonUtil; +import org.apache.http.HttpStatus; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; + +import static org.testng.Assert.assertEquals; + +/** + * class for MTLSCertificateValidator Test. + */ +@PrepareForTest({IdentityCommonUtil.class}) +@PowerMockIgnore({"jdk.internal.reflect.*"}) +public class MTLSCertificateValidatorTest extends PowerMockTestCase { + + MockHttpServletResponse response; + MockHttpServletRequest request; + FilterChain filterChain; + TokenFilter filter; + + @BeforeMethod + public void beforeMethod() throws ReflectiveOperationException, IOException, OpenBankingException { + + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + filterChain = Mockito.spy(FilterChain.class); + + List validators = new ArrayList<>(); + MTLSCertificateValidator mtlsCertificateValidator = Mockito.spy(MTLSCertificateValidator.class); + validators.add(mtlsCertificateValidator); + + filter = Mockito.spy(TokenFilter.class); + Mockito.doReturn(new DefaultTokenFilter()).when(filter).getDefaultTokenFilter(); + Mockito.doReturn(validators).when(filter).getValidators(); + PowerMockito.mockStatic(IdentityCommonUtil.class); + PowerMockito.when(IdentityCommonUtil.getMTLSAuthHeader()).thenReturn(TestConstants.CERTIFICATE_HEADER); + PowerMockito.when(IdentityCommonUtil.getRegulatoryFromSPMetaData("test")).thenReturn(true); + Map configMap = new HashMap<>(); + configMap.put(IdentityCommonConstants.ENABLE_TRANSPORT_CERT_AS_HEADER, true); + configMap.put(IdentityCommonConstants.CLIENT_CERTIFICATE_ENCODE, false); + IdentityExtensionsDataHolder.getInstance().setConfigurationMap(configMap); + + request.setParameter(IdentityCommonConstants.CLIENT_ID, "test"); + request.setAttribute(IdentityCommonConstants.JAVAX_SERVLET_REQUEST_CERTIFICATE, null); + + } + + @Test(description = "Test whether the expired certificate fails") + public void testMTLSCertValidationWithExpiredCertificate() throws IOException, ServletException { + + request.addHeader(TestConstants.CERTIFICATE_HEADER, TestConstants.EXPIRED_CERTIFICATE_CONTENT); + + filter.doFilter(request, response, filterChain); + Map responseMap = TestUtil.getResponse(response.getOutputStream()); + assertEquals(response.getStatus(), HttpStatus.SC_UNAUTHORIZED); + assertEquals(responseMap.get(IdentityCommonConstants.OAUTH_ERROR), "invalid_client"); + assertEquals(responseMap.get(IdentityCommonConstants.OAUTH_ERROR_DESCRIPTION), + "Invalid mutual TLS request. Client certificate is expired"); + + } + + @Test(description = "Test whether the expired certificate fails") + public void testMTLSCertValidationWithValidCertificate() throws IOException, ServletException { + + request.addHeader(TestConstants.CERTIFICATE_HEADER, TestConstants.CERTIFICATE_CONTENT); + + filter.doFilter(request, response, filterChain); + assertEquals(response.getStatus(), HttpStatus.SC_OK); + } +} diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/resources/testng.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/resources/testng.xml index cd41c6f2..f2b8a270 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/resources/testng.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.identity/src/test/resources/testng.xml @@ -29,6 +29,11 @@ + + + + + @@ -62,6 +67,9 @@ + + + @@ -125,4 +133,19 @@ + + + + + + + + + + + + + + + diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/pom.xml index 588d88eb..18e6a508 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/pom.xml @@ -14,13 +14,11 @@ ~ KIND, either express or implied. See the License for the ~ specific language governing permissions and limitations ~ under the License. - --> + --> open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml 4.0.0 @@ -39,7 +37,7 @@ org.eclipse.osgi - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -51,10 +49,6 @@ org.wso2.carbon.apimgt org.wso2.carbon.apimgt.impl - - org.wso2.carbon.identity.framework - org.wso2.carbon.identity.application.mgt.stub - org.mockito mockito-all @@ -204,8 +198,6 @@ org.wso2.carbon.apimgt.impl;version="${org.wso2.carbon.apimgt.version.range}", org.wso2.carbon.apimgt.impl.jwt;version="${org.wso2.carbon.apimgt.version.range}", org.wso2.carbon.authenticator.stub;version="${carbon.kernel.version.range}", - org.wso2.carbon.identity.application.common.model.xsd;version="${carbon.identity.framework.version.range}", - org.wso2.carbon.identity.application.mgt.stub;version="${carbon.identity.framework.version.range}", org.wso2.carbon.user.mgt.stub;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.oauth.stub;version="${org.wso2.carbon.identity.oauth.stub.version.range}", org.wso2.carbon.identity.oauth.stub.dto;version="${org.wso2.carbon.identity.oauth.stub.version.range}", diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerUtil.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerUtil.java index 6ef68c55..fed1c6be 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerUtil.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerUtil.java @@ -59,7 +59,10 @@ public class KeyManagerUtil { * * @return Session cookie as a String * @throws APIManagementException When failed to obtain the session cookie + * @deprecated ApplicationManagementService is used instead of SOAP API calls. */ + @Deprecated + @Generated(message = "Excluding from unit test coverage") public static String getSessionCookie() throws APIManagementException { String sessionCookie = ""; @@ -90,7 +93,10 @@ public static String getSessionCookie() throws APIManagementException { * * @param serviceClient Admin service client * @param sessionCookie session cookie as a string + * @deprecated ApplicationManagementService is used instead of SOAP API calls. */ + @Deprecated + @Generated(message = "Excluding from unit test coverage") public static void setAdminServiceSession(ServiceClient serviceClient, String sessionCookie) { Options userAdminOption = serviceClient.getOptions(); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/OBKeyManagerImpl.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/OBKeyManagerImpl.java index 306eb6ac..ee86cf1c 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/OBKeyManagerImpl.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/OBKeyManagerImpl.java @@ -26,7 +26,6 @@ import net.minidev.json.JSONObject; import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; -import org.apache.axis2.client.ServiceClient; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,16 +41,13 @@ import org.wso2.carbon.apimgt.impl.AMDefaultKeyManagerImpl; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; -import org.wso2.carbon.identity.application.common.model.xsd.ServiceProvider; -import org.wso2.carbon.identity.application.common.model.xsd.ServiceProviderProperty; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.common.model.ServiceProviderProperty; +import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants; import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; -import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceIdentityApplicationManagementException; import org.wso2.carbon.identity.oauth.IdentityOAuthAdminException; import org.wso2.carbon.identity.oauth.OAuthAdminService; -import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceIdentityOAuthAdminException; -import org.wso2.carbon.identity.oauth.stub.dto.OAuthConsumerAppDTO; -import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -65,45 +61,24 @@ public class OBKeyManagerImpl extends AMDefaultKeyManagerImpl implements OBKeyMa private static final Log log = LogFactory.getLog(OBKeyManagerImpl.class); + public static final String OAUTH2 = "oauth2"; + @Override public AccessTokenInfo getNewApplicationAccessToken(AccessTokenRequest tokenRequest) throws APIManagementException { try { - String applicationName = ""; - String sessionCookie = KeyManagerUtil.getSessionCookie(); - ServiceClient userAdminClient = KeyManagerDataHolder.getInstance() - .getUserAdminStub()._getServiceClient(); - KeyManagerUtil.setAdminServiceSession(userAdminClient, sessionCookie); - - ServiceClient oauthAppClient = KeyManagerDataHolder.getInstance().getOauthAdminServiceStub() - ._getServiceClient(); - KeyManagerUtil.setAdminServiceSession(oauthAppClient, sessionCookie); - - OAuthConsumerAppDTO oAuthConsumerAppDTO = KeyManagerDataHolder.getInstance().getOauthAdminServiceStub() - .getOAuthApplicationData(tokenRequest.getClientId()); - - if (oAuthConsumerAppDTO != null) { - applicationName = oAuthConsumerAppDTO.getApplicationName(); - } - - ServiceClient appMgtClient = KeyManagerDataHolder.getInstance() - .getIdentityApplicationManagementServiceStub()._getServiceClient(); - KeyManagerUtil.setAdminServiceSession(appMgtClient, sessionCookie); - - ServiceProvider serviceProvider = KeyManagerDataHolder.getInstance() - .getIdentityApplicationManagementServiceStub().getApplication(applicationName); - ServiceProviderProperty[] serviceProviderProperties = serviceProvider.getSpProperties(); - List spProperties = new ArrayList<>(Arrays.asList(serviceProviderProperties)); - - ServiceProviderProperty regulatoryProperty = spProperties.stream() - .filter(serviceProviderProperty -> serviceProviderProperty.getName() - .equalsIgnoreCase(OpenBankingConstants.REGULATORY)).findAny().orElse(null); - - if (regulatoryProperty != null && "true".equalsIgnoreCase(regulatoryProperty.getValue())) { - return null; + ApplicationManagementServiceImpl applicationManagementService = getApplicationMgmtServiceImpl(); + ServiceProvider serviceProvider = applicationManagementService.getServiceProviderByClientId( + tokenRequest.getClientId(), IdentityApplicationConstants.OAuth2.NAME, tenantDomain); + if (serviceProvider != null) { + ServiceProviderProperty regulatoryProperty = Arrays.stream(serviceProvider.getSpProperties()) + .filter(serviceProviderProperty -> serviceProviderProperty.getName() + .equalsIgnoreCase(OpenBankingConstants.REGULATORY)).findAny().orElse(null); + if (regulatoryProperty != null && "true".equalsIgnoreCase(regulatoryProperty.getValue())) { + return null; + } } - } catch (RemoteException | IdentityApplicationManagementServiceIdentityApplicationManagementException | - OAuthAdminServiceIdentityOAuthAdminException e) { + } catch (IdentityApplicationManagementException e) { log.error("Error while generating keys. ", e); } return super.getNewApplicationAccessToken(tokenRequest); @@ -239,16 +214,16 @@ public OAuthApplicationInfo createApplication(OAuthAppRequest oauthAppRequest) t String tenantDomain = ServiceProviderUtils.getSpTenantDomain(oAuthApplicationInfo.getClientId()); updateSpProperties(appName, tenantDomain, username, additionalProperties, true); - org.wso2.carbon.identity.application.common.model.ServiceProvider appServiceProvider = - getApplicationMgmtServiceImpl().getServiceProvider(appName, tenantDomain); - org.wso2.carbon.identity.application.common.model.ServiceProviderProperty regulatoryProperty = - getSpPropertyFromSPMetaData(OpenBankingConstants.REGULATORY, appServiceProvider.getSpProperties()); + ServiceProvider appServiceProvider = getApplicationMgmtServiceImpl() + .getServiceProvider(appName, tenantDomain); + ServiceProviderProperty regulatoryProperty = getSpPropertyFromSPMetaData( + OpenBankingConstants.REGULATORY, appServiceProvider.getSpProperties()); if (regulatoryProperty != null) { if (Boolean.parseBoolean(regulatoryProperty.getValue())) { OAuthAppRequest updatedOauthAppRequest = oauthAppRequest; - org.wso2.carbon.identity.application.common.model.ServiceProviderProperty appNameProperty = - getSpPropertyFromSPMetaData("DisplayName", appServiceProvider.getSpProperties()); + ServiceProviderProperty appNameProperty = getSpPropertyFromSPMetaData("DisplayName", + appServiceProvider.getSpProperties()); if (appNameProperty != null) { updatedOauthAppRequest.getOAuthApplicationInfo().setClientName(appNameProperty.getValue()); } @@ -280,16 +255,16 @@ public OAuthApplicationInfo updateApplication(OAuthAppRequest oAuthAppRequest) t String clientId = oAuthApplicationInfo.getClientId(); // There is no way to identify the client type in here. So we have to hardcode "oauth2" as the client type try { - org.wso2.carbon.identity.application.common.model.ServiceProvider serviceProvider = - getApplicationMgmtServiceImpl().getServiceProviderByClientId(clientId, "oauth2", tenantDomain); + ServiceProvider serviceProvider = getApplicationMgmtServiceImpl() + .getServiceProviderByClientId(clientId, OAUTH2, tenantDomain); doPreUpdateApplication(oAuthAppRequest, additionalProperties, serviceProvider); String appName = serviceProvider.getApplicationName(); String username = (String) oAuthApplicationInfo.getParameter(ApplicationConstants.OAUTH_CLIENT_USERNAME); updateSpProperties(appName, tenantDomain, username, additionalProperties, false); } catch (IdentityApplicationManagementException e) { String errMsg = "Cannot find Service provider application for client Id " + clientId; - log.error(errMsg); - throw new APIManagementException(errMsg, ExceptionCodes.OAUTH2_APP_RETRIEVAL_FAILED); + log.error(errMsg); + throw new APIManagementException(errMsg, ExceptionCodes.OAUTH2_APP_RETRIEVAL_FAILED); } oAuthApplicationInfo = super.updateApplication(oAuthAppRequest); @@ -308,7 +283,7 @@ public OAuthApplicationInfo retrieveApplication(String consumerKey) throws APIMa getApplicationMgmtServiceImpl().getServiceProvider(name, tenantDomain); // Iterate OB specific additional properties to check whether they override the value of any predefined // sp properties in application management listeners - List spProperties = + List spProperties = new ArrayList<>(Arrays.asList(appServiceProvider.getSpProperties())); return updateAdditionalProperties(oAuthApplicationInfo, spProperties); } catch (IdentityApplicationManagementException | OpenBankingException e) { @@ -332,33 +307,30 @@ protected void updateSpProperties(String spAppName, String tenantDomain, String try { org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO oAuthConsumerAppDTO = getOAuthAdminService(). getOAuthApplicationDataByAppName(spAppName); - org.wso2.carbon.identity.application.common.model.ServiceProvider serviceProvider = - getApplicationMgmtServiceImpl().getServiceProvider(spAppName, tenantDomain); - + ServiceProvider serviceProvider = getApplicationMgmtServiceImpl() + .getServiceProvider(spAppName, tenantDomain); doPreUpdateSpApp(oAuthConsumerAppDTO, serviceProvider, additionalProperties, isCreateApp); // Iterate OB specific additional properties to check whether they override the value of any predefined // sp properties in application management listeners - List spProperties = + List spProperties = new ArrayList<>(Arrays.asList(serviceProvider.getSpProperties())); for (Map.Entry propertyElement : additionalProperties.entrySet()) { - org.wso2.carbon.identity.application.common.model.ServiceProviderProperty overridenSPproperty - = spProperties.stream().filter(serviceProviderProperty -> serviceProviderProperty.getName() - .equalsIgnoreCase(propertyElement.getKey())).findAny().orElse(null); + ServiceProviderProperty overridenSPproperty = spProperties.stream().filter( + serviceProviderProperty -> serviceProviderProperty.getName() + .equalsIgnoreCase(propertyElement.getKey())).findAny().orElse(null); // If SP property is overridden, remove old SP property and add the new one if (overridenSPproperty != null) { spProperties.remove(overridenSPproperty); overridenSPproperty.setValue(propertyElement.getValue()); spProperties.add(overridenSPproperty); } else { - org.wso2.carbon.identity.application.common.model.ServiceProviderProperty additionalProperty = - new org.wso2.carbon.identity.application.common.model.ServiceProviderProperty(); + ServiceProviderProperty additionalProperty = new ServiceProviderProperty(); additionalProperty.setName(propertyElement.getKey()); additionalProperty.setValue(propertyElement.getValue()); spProperties.add(additionalProperty); } } - serviceProvider.setSpProperties(spProperties.toArray( - new org.wso2.carbon.identity.application.common.model.ServiceProviderProperty[0])); + serviceProvider.setSpProperties(spProperties.toArray(new ServiceProviderProperty[0])); try { getApplicationMgmtServiceImpl().updateApplication(serviceProvider, tenantDomain, username); if (log.isDebugEnabled()) { @@ -395,13 +367,12 @@ protected void updateSpProperties(String spAppName, String tenantDomain, String * @return oAuth application Info */ protected OAuthApplicationInfo updateAdditionalProperties(OAuthApplicationInfo oAuthApplicationInfo, - List spProperties) { + List spProperties) { Map> keyManagerAdditionalProperties = OpenBankingConfigParser.getInstance() .getKeyManagerAdditionalProperties(); for (String key : keyManagerAdditionalProperties.keySet()) { - for (org.wso2.carbon.identity.application.common.model.ServiceProviderProperty spProperty : spProperties) { + for (ServiceProviderProperty spProperty : spProperties) { if (spProperty.getName().equalsIgnoreCase(key)) { ((HashMap) oAuthApplicationInfo.getParameter( APIConstants.JSON_ADDITIONAL_PROPERTIES)).put(key, spProperty.getValue()); @@ -421,8 +392,7 @@ protected OAuthApplicationInfo updateAdditionalProperties(OAuthApplicationInfo o public void validateAdditionalProperties(Map obAdditionalProperties) throws APIManagementException { - OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil - .getOBKeyManagerExtensionImpl(); + OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil.getOBKeyManagerExtensionImpl(); if (obKeyManagerExtensionImpl != null) { obKeyManagerExtensionImpl.validateAdditionalProperties(obAdditionalProperties); } @@ -437,8 +407,7 @@ public void validateAdditionalProperties(Map obAdditio @Generated(message = "Excluding from code coverage since the method body is at toolkit") public void doPreCreateApplication(OAuthAppRequest oAuthAppRequest, HashMap additionalProperties) throws APIManagementException { - OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil - .getOBKeyManagerExtensionImpl(); + OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil.getOBKeyManagerExtensionImpl(); if (obKeyManagerExtensionImpl != null) { obKeyManagerExtensionImpl.doPreCreateApplication(oAuthAppRequest, additionalProperties); } @@ -452,11 +421,8 @@ public void doPreCreateApplication(OAuthAppRequest oAuthAppRequest, HashMap additionalProperties, - org.wso2.carbon.identity.application.common.model.ServiceProvider - serviceProvider) - throws APIManagementException { - OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil - .getOBKeyManagerExtensionImpl(); + ServiceProvider serviceProvider) throws APIManagementException { + OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil.getOBKeyManagerExtensionImpl(); if (obKeyManagerExtensionImpl != null) { obKeyManagerExtensionImpl.doPreUpdateApplication(oAuthAppRequest, additionalProperties, serviceProvider); } @@ -472,12 +438,11 @@ public void doPreUpdateApplication(OAuthAppRequest oAuthAppRequest, HashMap additionalProperties, boolean isCreateApp) throws APIManagementException { - OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil - .getOBKeyManagerExtensionImpl(); + OBKeyManagerExtensionInterface obKeyManagerExtensionImpl = KeyManagerUtil.getOBKeyManagerExtensionImpl(); if (obKeyManagerExtensionImpl != null) { obKeyManagerExtensionImpl.doPreUpdateSpApp(oAuthConsumerAppDTO, serviceProvider, additionalProperties, isCreateApp); @@ -495,9 +460,8 @@ protected OAuthAdminService getOAuthAdminService() { return new OAuthAdminService(); } - protected org.wso2.carbon.identity.application.common.model.ServiceProviderProperty getSpPropertyFromSPMetaData( - String propertyName, - org.wso2.carbon.identity.application.common.model.ServiceProviderProperty[] spProperties) { + protected ServiceProviderProperty getSpPropertyFromSPMetaData(String propertyName, + ServiceProviderProperty[] spProperties) { return Arrays.asList(spProperties).stream().filter(serviceProviderProperty -> serviceProviderProperty.getName() .equalsIgnoreCase(propertyName)).findAny().orElse(null); diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/internal/KeyManagerDataHolder.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/internal/KeyManagerDataHolder.java index 6e3b9060..0e35ac0e 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/internal/KeyManagerDataHolder.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/main/java/com/wso2/openbanking/accelerator/keymanager/internal/KeyManagerDataHolder.java @@ -22,7 +22,6 @@ import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService; import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub; -import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceStub; import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceStub; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.mgt.stub.UserAdminStub; @@ -41,7 +40,6 @@ public class KeyManagerDataHolder { public static final String AUTHENTICATION_ADMIN_SERVICE = "AuthenticationAdmin"; public static final String USER_ADMIN_SERVICE = "UserAdmin"; public static final String OAUTH_ADMIN_SERVICE = "OAuthAdminService"; - private IdentityApplicationManagementServiceStub identityApplicationManagementServiceStub; private AuthenticationAdminStub authenticationAdminStub; private OAuthAdminServiceStub oAuthAdminServiceStub; private UserAdminStub userAdminStub; @@ -75,23 +73,6 @@ public void setUserAdminStub(UserAdminStub userAdminStub) { this.userAdminStub = userAdminStub; } - public IdentityApplicationManagementServiceStub getIdentityApplicationManagementServiceStub() - throws AxisFault { - - if (identityApplicationManagementServiceStub == null) { - String appMgtServiceURL = backendServerURL + IDENTITY_APPLICATION_MGT_SERVICE; - identityApplicationManagementServiceStub = new IdentityApplicationManagementServiceStub( - appMgtServiceURL); - } - return identityApplicationManagementServiceStub; - } - - public void setIdentityApplicationManagementServiceStub(IdentityApplicationManagementServiceStub - identityApplicationManagementServiceStub) { - - this.identityApplicationManagementServiceStub = identityApplicationManagementServiceStub; - } - public AuthenticationAdminStub getAuthenticationAdminStub() throws AxisFault { if (authenticationAdminStub == null) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/test/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerTest.java b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/test/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerTest.java index a493ff2e..565e0d5b 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/test/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerTest.java +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.keymanager/src/test/java/com/wso2/openbanking/accelerator/keymanager/KeyManagerTest.java @@ -52,11 +52,10 @@ import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService; import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub; import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException; -import org.wso2.carbon.identity.application.common.model.xsd.ServiceProvider; -import org.wso2.carbon.identity.application.common.model.xsd.ServiceProviderProperty; +import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.common.model.ServiceProviderProperty; import org.wso2.carbon.identity.application.mgt.ApplicationManagementServiceImpl; -import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceIdentityApplicationManagementException; -import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceStub; import org.wso2.carbon.identity.oauth.OAuthAdminService; import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceIdentityOAuthAdminException; import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceStub; @@ -87,9 +86,6 @@ public class KeyManagerTest extends PowerMockTestCase { @Mock private OAuthAdminServiceStub oAuthAdminServiceStub; - @Mock - private IdentityApplicationManagementServiceStub identityApplicationManagementServiceStub; - @Mock private AuthenticationAdminStub authenticationAdminStub; @@ -174,9 +170,9 @@ public IObjectFactory getObjectFactory() { @Test public void testGetNewApplicationAccessToken() throws APIManagementException, RemoteException, OAuthAdminServiceIdentityOAuthAdminException, - IdentityApplicationManagementServiceIdentityApplicationManagementException, - LoginAuthenticationExceptionException { + LoginAuthenticationExceptionException, IdentityApplicationManagementException { + OBKeyManagerImpl obKeyManager = spy(new OBKeyManagerImplMock()); OAuthConsumerAppDTO oAuthConsumerAppDTO = new OAuthConsumerAppDTO(); oAuthConsumerAppDTO.setApplicationName("AppName"); @@ -204,8 +200,6 @@ public void testGetNewApplicationAccessToken() throws APIManagementException, Re KeyManagerDataHolder.getInstance().setApiManagerConfiguration(apiManagerConfigurationService); KeyManagerDataHolder.getInstance().setAuthenticationAdminStub(authenticationAdminStub); KeyManagerDataHolder.getInstance().setOauthAdminServiceStub(oAuthAdminServiceStub); - KeyManagerDataHolder.getInstance() - .setIdentityApplicationManagementServiceStub(identityApplicationManagementServiceStub); AccessTokenRequest accessTokenRequest = new AccessTokenRequest(); @@ -227,16 +221,10 @@ public void testGetNewApplicationAccessToken() throws APIManagementException, Re Mockito.when(oAuthAdminServiceStub.getOAuthApplicationData(anyString())) .thenReturn(oAuthConsumerAppDTO); - Mockito.when(keyManagerDataHolder.getIdentityApplicationManagementServiceStub()) - .thenReturn(identityApplicationManagementServiceStub); - - Mockito.when(identityApplicationManagementServiceStub._getServiceClient()).thenReturn(serviceClient); - Mockito.when(identityApplicationManagementServiceStub - .getApplication(oAuthConsumerAppDTO.getApplicationName())) - .thenReturn(serviceProvider); - + Mockito.when(obKeyManager.getApplicationMgmtServiceImpl()).thenReturn(applicationManagementServiceImpl); + Mockito.when(applicationManagementServiceImpl.getServiceProviderByClientId( + anyString(), anyString(), anyString())).thenReturn(serviceProvider); AccessTokenInfo accessTokenInfo = obKeyManager.getNewApplicationAccessToken(accessTokenRequest); - Assert.assertTrue(accessTokenInfo == null); } @@ -249,7 +237,7 @@ public void testUpdateAdditionalProperties() { keyManagerAdditionalProperties.put(dummyPropertyName2, property); when(openBankingConfigParser.getKeyManagerAdditionalProperties()).thenReturn(keyManagerAdditionalProperties); - spy(org.wso2.carbon.identity.application.common.model.ServiceProvider.class); + spy(ServiceProvider.class); List spProperties = new ArrayList<>(); @@ -305,8 +293,7 @@ public void testUpdateSpProperties() throws Exception { spProperties[0] = (spProperty1); spProperties[1] = (spProperty2); - org.wso2.carbon.identity.application.common.model.ServiceProvider serviceProvider = - spy(org.wso2.carbon.identity.application.common.model.ServiceProvider.class); + ServiceProvider serviceProvider = spy(ServiceProvider.class); doNothing().when(applicationManagementServiceImpl).updateApplication(Mockito.anyObject(), Mockito.anyString(), Mockito.anyString()); @@ -344,8 +331,7 @@ public void testUpdateSpProperties() throws Exception { org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO oAuthConsumerAppDTOdummy = new org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO(); - org.wso2.carbon.identity.application.common.model.ServiceProvider serviceProviderDummy = - new org.wso2.carbon.identity.application.common.model.ServiceProvider(); + ServiceProvider serviceProviderDummy = new ServiceProvider(); HashMap dummyMap = new HashMap<>(); doNothing().when(obKeyManager).doPreUpdateSpApp(oAuthConsumerAppDTOdummy, serviceProviderDummy, dummyMap, @@ -460,7 +446,7 @@ public Object[][] validateOAuthAppCreationPropertiesDataProvider() { @Test(dataProvider = "validateOAuthAppCreationPropertiesDataProvider", description = "Validate user inputs for application creation") public void testValidateOAuthAppCreationProperties(Map> - keyManagerAdditionalProperties, + keyManagerAdditionalProperties, List applicationConfigurationsList, String valuesForProperties, Class exceptionType) { diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/com.wso2.openbanking.accelerator.runtime.identity.authn.filter/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/com.wso2.openbanking.accelerator.runtime.identity.authn.filter/pom.xml index 04235d4b..1b934f36 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/com.wso2.openbanking.accelerator.runtime.identity.authn.filter/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/com.wso2.openbanking.accelerator.runtime.identity.authn.filter/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + com.wso2.openbanking.accelerator.runtime - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../pom.xml @@ -57,7 +55,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/pom.xml index 8e9b4843..edc3b4c5 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.runtime/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml diff --git a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.service.activator/pom.xml b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.service.activator/pom.xml index 905e0d12..b80a60de 100644 --- a/open-banking-accelerator/components/com.wso2.openbanking.accelerator.service.activator/pom.xml +++ b/open-banking-accelerator/components/com.wso2.openbanking.accelerator.service.activator/pom.xml @@ -16,14 +16,13 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../pom.xml @@ -37,7 +36,7 @@ org.wso2.carbon.core - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/pom.xml b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/pom.xml index 6387d695..61986ede 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/pom.xml +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/pom.xml @@ -16,15 +16,13 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml @@ -39,11 +37,11 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -61,11 +59,11 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao provided @@ -102,7 +100,7 @@ org.wso2.carbon.identity.application.authenticator.push - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.event.notifications.service diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/admin/model/ConsentAdminHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/admin/model/ConsentAdminHandler.java index e1c6cb9d..65f514bf 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/admin/model/ConsentAdminHandler.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/admin/model/ConsentAdminHandler.java @@ -42,21 +42,21 @@ public interface ConsentAdminHandler { /** * Method to handle the temporary retention data syncing with the retention database. * @param consentAdminData consentAdminData - * @throws ConsentException + * @throws ConsentException if any error occurs while syncing the retention database */ public void handleTemporaryRetentionDataSyncing(ConsentAdminData consentAdminData) throws ConsentException; /** * Method to handle the consent status audit search. * @param consentAdminData consentAdminData - * @throws ConsentException + * @throws ConsentException if any error occurs while searching the consent status audit */ public void handleConsentStatusAuditSearch(ConsentAdminData consentAdminData) throws ConsentException; /** * Method to handle the consent file search. * @param consentAdminData consentAdminData - * @throws ConsentException + * @throws ConsentException if any error occurs while searching the consent file */ public void handleConsentFileSearch(ConsentAdminData consentAdminData) throws ConsentException; diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentPersistStep.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentPersistStep.java index a0cc599e..47a06698 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentPersistStep.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentPersistStep.java @@ -20,18 +20,22 @@ package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl; import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist.ConsentPersistenceHandler; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistStep; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.extensions.common.factory.AcceleratorConsentExtensionFactory; import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.util.ArrayList; + /** * Consent persist step default implementation. @@ -66,16 +70,57 @@ public void execute(ConsentPersistData consentPersistData) throws ConsentExcepti "Auth resource not available in consent data"); } - //Bind the user and accounts with the consent - String type = consentResource.getConsentType(); - ConsentPersistenceHandler consentPersistenceHandler = AcceleratorConsentExtensionFactory - .getConsentPersistenceHandler(type); + consentPersist(consentPersistData, consentResource); - consentPersistenceHandler.consentPersist(consentPersistData, consentResource); } catch (ConsentManagementException e) { throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, "Exception occured while persisting consent"); } } + + /** + * This method defined to handle consent persistence based on the consent type. + * + * @param consentPersistData Consent Persist Data Object + * @param consentResource Consent Resource Object + * @throws ConsentManagementException + */ + public static void consentPersist(ConsentPersistData consentPersistData, ConsentResource consentResource) + throws ConsentManagementException { + + ConsentData consentData = consentPersistData.getConsentData(); + + JSONObject payload = consentPersistData.getPayload(); + + if (payload.get(ConsentExtensionConstants.ACCOUNT_IDS) == null || + !(payload.get(ConsentExtensionConstants.ACCOUNT_IDS) instanceof JSONArray)) { + log.error(ErrorConstants.ACCOUNT_ID_NOT_FOUND_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.ACCOUNT_ID_NOT_FOUND_ERROR); + } + + JSONArray accountIds = (JSONArray) payload.get(ConsentExtensionConstants.ACCOUNT_IDS); + ArrayList accountIdsString = new ArrayList<>(); + for (Object account : accountIds) { + if (!(account instanceof String)) { + log.error(ErrorConstants.ACCOUNT_ID_FORMAT_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.ACCOUNT_ID_FORMAT_ERROR); + } + accountIdsString.add((String) account); + } + String consentStatus; + + if (consentPersistData.getApproval()) { + consentStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; + } else { + consentStatus = ConsentExtensionConstants.REJECTED_STATUS; + } + + ConsentExtensionsDataHolder.getInstance().getConsentCoreService() + .bindUserAccountsToConsent(consentResource, consentData.getUserId(), + consentData.getAuthResource().getAuthorizationID(), accountIdsString, consentStatus, + consentStatus); + } } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentRetrievalStep.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentRetrievalStep.java index a22af70d..0deca7b5 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentRetrievalStep.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/DefaultConsentRetrievalStep.java @@ -16,11 +16,9 @@ * under the License. */ - package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl; import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval.ConsentRetrievalHandler; import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentRetrievalStep; import com.wso2.openbanking.accelerator.consent.extensions.authorize.utils.ConsentRetrievalUtil; @@ -28,7 +26,6 @@ import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.extensions.common.factory.AcceleratorConsentExtensionFactory; import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; import com.wso2.openbanking.accelerator.consent.mgt.dao.models.AuthorizationResource; import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; @@ -44,7 +41,6 @@ public class DefaultConsentRetrievalStep implements ConsentRetrievalStep { private static final Log log = LogFactory.getLog(DefaultConsentRetrievalStep.class); - ConsentRetrievalHandler consentRetrievalHandler; @Override public void execute(ConsentData consentData, JSONObject jsonObject) throws ConsentException { @@ -66,7 +62,7 @@ public void execute(ConsentData consentData, JSONObject jsonObject) throws Conse "executed successfully before default consent persist step"); } String requestObject = ConsentRetrievalUtil.extractRequestObject(consentData.getSpQueryParams()); - consentId = ConsentRetrievalUtil.extractConsentId(requestObject); + consentId = ConsentRetrievalUtil.extractConsentId(requestObject); consentData.setConsentId(consentId); } ConsentResource consentResource = consentCoreService.getConsent(consentId, false); @@ -101,7 +97,6 @@ public void execute(ConsentData consentData, JSONObject jsonObject) throws Conse JSONArray accountsJSON = ConsentRetrievalUtil.appendDummyAccountID(); jsonObject.appendField(ConsentExtensionConstants.ACCOUNTS, accountsJSON); - } catch (ConsentException e) { JSONObject errorObj = (JSONObject) e.getPayload(); JSONArray errorList = (JSONArray) errorObj.get("Errors"); @@ -113,18 +108,15 @@ public void execute(ConsentData consentData, JSONObject jsonObject) throws Conse "Exception occurred while getting consent data"); } } + /** * Method to retrieve consent related data from the initiation payload. - * @param consentResource - * @return - * @throws ConsentException + * @param consentResource Consent Resource + * @return consent */ - public JSONArray getConsentDataSet(ConsentResource consentResource) - throws ConsentException { + public JSONArray getConsentDataSet(ConsentResource consentResource) { - String type = consentResource.getConsentType(); - consentRetrievalHandler = AcceleratorConsentExtensionFactory.getConsentRetrievalHandler(type); - return consentRetrievalHandler.getConsentDataSet(consentResource); + return ConsentRetrievalUtil.getConsentData(consentResource); } } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/AccountConsentPersistenceHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/AccountConsentPersistenceHandler.java deleted file mode 100644 index ecc3d19e..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/AccountConsentPersistenceHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist; - -import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; - -/** - * Class to handle Accounts Consent data persistence for Authorize. - */ -public class AccountConsentPersistenceHandler implements ConsentPersistenceHandler { - - private static final Log log = LogFactory.getLog(AccountConsentPersistenceHandler.class); - - /** - * Abstract method defined to handle consent persistence based on the consent type. - * - * @param consentPersistData Consent Persist Data Object - * @param consentResource Consent Resource Object - * @throws ConsentManagementException - */ - @Override - public void consentPersist(ConsentPersistData consentPersistData, ConsentResource consentResource) - throws ConsentManagementException { - - ConsentData consentData = consentPersistData.getConsentData(); - - JSONObject payload = consentPersistData.getPayload(); - - if (payload.get("accountIds") == null || !(payload.get("accountIds") instanceof JSONArray)) { - log.error("Account IDs not available in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs not available in persist request"); - } - - JSONArray accountIds = (JSONArray) payload.get("accountIds"); - ArrayList accountIdsString = new ArrayList<>(); - for (Object account : accountIds) { - if (!(account instanceof String)) { - log.error("Account IDs format error in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs format error in persist request"); - } - accountIdsString.add((String) account); - } - String consentStatus; - String authStatus; - - if (consentPersistData.getApproval()) { - consentStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - authStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - } else { - consentStatus = ConsentExtensionConstants.REJECTED_STATUS; - authStatus = ConsentExtensionConstants.REJECTED_STATUS; - } - - ConsentExtensionsDataHolder.getInstance().getConsentCoreService() - .bindUserAccountsToConsent(consentResource, consentData.getUserId(), - consentData.getAuthResource().getAuthorizationID(), accountIdsString, authStatus, - consentStatus); - - } - -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/CofConsentPersistenceHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/CofConsentPersistenceHandler.java deleted file mode 100644 index 10868a2f..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/CofConsentPersistenceHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist; - -import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.common.util.ErrorConstants; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; - - -/** - * Class to handle COF Consent data persistence for Authorize. - */ -public class CofConsentPersistenceHandler implements ConsentPersistenceHandler { - - private static final Log log = LogFactory.getLog(CofConsentPersistenceHandler.class); - - /** - * Abstract method defined to handle consent persistence based on the consent type. - * - * @param consentPersistData Consent Persist Data Object - * @param consentResource Consent Resource Object - * @throws ConsentManagementException - */ - @Override - public void consentPersist(ConsentPersistData consentPersistData, ConsentResource consentResource) - throws ConsentManagementException { - - ConsentData consentData = consentPersistData.getConsentData(); - - JSONObject payload = consentPersistData.getPayload(); - - if (payload.get("accountIds") == null || !(payload.get("accountIds") instanceof JSONArray)) { - log.error("Account IDs not available in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs not available in persist request"); - } - - JSONArray accountIds = (JSONArray) payload.get("accountIds"); - ArrayList accountIdsString = new ArrayList<>(); - for (Object account : accountIds) { - if (!(account instanceof String)) { - log.error("Account IDs format error in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs format error in persist request"); - } - accountIdsString.add((String) account); - } - String consentStatus; - String authStatus; - - if (consentPersistData.getApproval()) { - consentStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - authStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - } else { - consentStatus = ConsentExtensionConstants.REJECTED_STATUS; - authStatus = ConsentExtensionConstants.REJECTED_STATUS; - } - //Check whether account Id exists - if (!payload.containsKey(ConsentExtensionConstants.COF_ACCOUNT)) { - log.error(ErrorConstants.ACCOUNT_ID_NOT_FOUND_ERROR); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - ErrorConstants.ACCOUNT_ID_NOT_FOUND_ERROR); - } - //Check whether account Id is in String format - if (!(payload.get(ConsentExtensionConstants.COF_ACCOUNT) instanceof String)) { - log.error(ErrorConstants.ACCOUNT_ID_FORMAT_ERROR); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - ErrorConstants.ACCOUNT_ID_FORMAT_ERROR); - } - ConsentExtensionsDataHolder.getInstance().getConsentCoreService() - .bindUserAccountsToConsent(consentResource, consentData.getUserId(), - consentData.getAuthResource().getAuthorizationID(), accountIdsString, authStatus, - consentStatus); - } - -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/ConsentPersistenceHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/ConsentPersistenceHandler.java deleted file mode 100644 index e7ad50c2..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/ConsentPersistenceHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist; - -import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; - - -/** - * Interface to handle Consent data persistence for Authorize. - */ -public interface ConsentPersistenceHandler { - - /** - * Abstract method defined to handle consent persistence based on the consent type. - * - * @param consentPersistData Consent Persist Data Object - * @param consentResource Consent Resource Object - * @throws ConsentManagementException - */ - void consentPersist(ConsentPersistData consentPersistData, ConsentResource consentResource) - throws ConsentManagementException; - -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/PaymentConsentPersistenceHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/PaymentConsentPersistenceHandler.java deleted file mode 100644 index bd70f9f8..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/persist/PaymentConsentPersistenceHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist; - -import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; - - -/** - * Class to handle payments Consent data persistence for Authorize. - */ -public class PaymentConsentPersistenceHandler implements ConsentPersistenceHandler { - - private static final Log log = LogFactory.getLog(PaymentConsentPersistenceHandler.class); - - /** - * Abstract method defined to handle consent persistence based on the consent type. - * - * @param consentPersistData Consent Persist Data Object - * @param consentResource Consent Resource Object - * @throws ConsentManagementException - */ - @Override - public void consentPersist(ConsentPersistData consentPersistData, ConsentResource consentResource) - throws ConsentManagementException { - - ConsentData consentData = consentPersistData.getConsentData(); - boolean isApproved = consentPersistData.getApproval(); - JSONObject payload = consentPersistData.getPayload(); - - if (payload.get("accountIds") == null || !(payload.get("accountIds") instanceof JSONArray)) { - log.error("Account IDs not available in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs not available in persist request"); - } - - JSONArray accountIds = (JSONArray) payload.get("accountIds"); - ArrayList accountIdsString = new ArrayList<>(); - for (Object account : accountIds) { - if (!(account instanceof String)) { - log.error("Account IDs format error in persist request"); - throw new ConsentException(ResponseStatus.BAD_REQUEST, - "Account IDs format error in persist request"); - } - accountIdsString.add((String) account); - } - String consentStatus; - String authStatus; - - if (isApproved) { - consentStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - authStatus = ConsentExtensionConstants.AUTHORIZED_STATUS; - } else { - consentStatus = ConsentExtensionConstants.REJECTED_STATUS; - authStatus = ConsentExtensionConstants.REJECTED_STATUS; - } - - ConsentExtensionsDataHolder.getInstance().getConsentCoreService() - .bindUserAccountsToConsent(consentResource, consentData.getUserId(), - consentData.getAuthResource().getAuthorizationID(), accountIdsString, authStatus, - consentStatus); - - } -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/AccountConsentRetrievalHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/AccountConsentRetrievalHandler.java deleted file mode 100644 index b73be77f..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/AccountConsentRetrievalHandler.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval; - - -import com.wso2.openbanking.accelerator.common.util.ErrorConstants; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.utils.ConsentRetrievalUtil; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; -import net.minidev.json.parser.ParseException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Class to handle Account Consent data retrieval for Authorize. - */ -public class AccountConsentRetrievalHandler implements ConsentRetrievalHandler { - - private static final Log log = LogFactory.getLog(AccountConsentRetrievalHandler.class); - - /** - * Method defined to retrieve the Account consent related data in the authorization flow to send them to the. - * consent page to get PSU consent - * - * @param consentResource Consent Resource parameter containing consent related information retrieved from database - * @return consentDataJSON - * @throws ConsentException - */ - @Override - public JSONArray getConsentDataSet(ConsentResource consentResource) - throws ConsentException { - - try { - String receiptString = consentResource.getReceipt(); - Object receiptJSON = new JSONParser(JSONParser.MODE_PERMISSIVE).parse(receiptString); - - //Checking whether the request body is in JSON format - if (!(receiptJSON instanceof JSONObject)) { - log.error(ErrorConstants.NOT_JSON_OBJECT_ERROR); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.NOT_JSON_OBJECT_ERROR); - } - - //Checking whether the consent status is valid - if (!consentResource.getCurrentStatus().equals(ConsentExtensionConstants.AWAITING_AUTH_STATUS)) { - log.error(ErrorConstants.STATE_INVALID_ERROR); - //Currently throwing error as 400 response. Developer also have the option of appending a field IS_ERROR - // to the jsonObject and showing it to the user in the webapp. If so, the IS_ERROR have to be checked in - // any later steps. - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.STATE_INVALID_ERROR); - } - - JSONArray consentDataJSON = new JSONArray(); - - JSONObject receipt = (JSONObject) receiptJSON; - - //Adding Permissions - JSONObject data = (JSONObject) receipt.get(ConsentExtensionConstants.DATA); - JSONArray permissions = (JSONArray) data.get(ConsentExtensionConstants.PERMISSIONS); - JSONObject jsonElementPermissions = new JSONObject(); - jsonElementPermissions.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.PERMISSIONS); - jsonElementPermissions.appendField(ConsentExtensionConstants.DATA_SIMPLE, permissions); - consentDataJSON.add(jsonElementPermissions); - - //Adding Expiration Date Time - if (data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE) != null) { - - if (!ConsentRetrievalUtil - .validateExpiryDateTime(data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE))) { - log.error(ErrorConstants.CONSENT_EXPIRED); - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.CONSENT_EXPIRED); - } - String expiry = data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE); - JSONArray expiryArray = new JSONArray(); - expiryArray.add(expiry); - - JSONObject jsonElementExpiry = new JSONObject(); - jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.EXPIRATION_DATE_TITLE); - jsonElementExpiry.appendField(ConsentExtensionConstants.DATA_SIMPLE, expiryArray); - consentDataJSON.add(jsonElementExpiry); - } - - //Adding Transaction From Date Time - if (data.getAsString(ConsentExtensionConstants.TRANSACTION_FROM_DATE) != null) { - String fromDateTime = data.getAsString(ConsentExtensionConstants.TRANSACTION_FROM_DATE); - JSONArray fromDateTimeArray = new JSONArray(); - fromDateTimeArray.add(fromDateTime); - - JSONObject jsonElementFromDateTime = new JSONObject(); - jsonElementFromDateTime.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.TRANSACTION_FROM_DATE_TITLE); - jsonElementFromDateTime.appendField(ConsentExtensionConstants.DATA_SIMPLE, fromDateTimeArray); - consentDataJSON.add(jsonElementFromDateTime); - } - - //Adding Transaction To Date Time - if (data.getAsString(ConsentExtensionConstants.TRANSACTION_TO_DATE) != null) { - String toDateTime = data.getAsString(ConsentExtensionConstants.TRANSACTION_TO_DATE); - JSONArray toDateTimeArray = new JSONArray(); - toDateTimeArray.add(toDateTime); - - JSONObject jsonElementToDateTime = new JSONObject(); - jsonElementToDateTime.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.TRANSACTION_TO_DATE_TITLE); - jsonElementToDateTime.appendField(ConsentExtensionConstants.DATA_SIMPLE, toDateTimeArray); - consentDataJSON.add(jsonElementToDateTime); - } - - return consentDataJSON; - } catch (ParseException e) { - log.error("Exception occurred while getting consent data. Caused by: ", e); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.CONSENT_RETRIEVAL_ERROR); - } - } -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/CofConsentRetrievalHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/CofConsentRetrievalHandler.java deleted file mode 100644 index 73f1017c..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/CofConsentRetrievalHandler.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval; - -import com.wso2.openbanking.accelerator.common.util.ErrorConstants; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.utils.ConsentRetrievalUtil; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; -import net.minidev.json.parser.ParseException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Class to handle Confirmation of Funds Consent data retrieval for Authorize. - */ -public class CofConsentRetrievalHandler implements ConsentRetrievalHandler { - - private static final Log log = LogFactory.getLog(CofConsentRetrievalHandler.class); - - /** - * Method defined to retrieve the COF consent related data in the authorization flow to send them to the - * consent page to get PSU consent. - * - * @param consentResource Consent Resource parameter containing consent related information retrieved from database - * @return - * @throws ConsentException - */ - @Override - public JSONArray getConsentDataSet(ConsentResource consentResource) throws ConsentException { - - try { - String receiptString = consentResource.getReceipt(); - Object receiptJSON = new JSONParser(JSONParser.MODE_PERMISSIVE).parse(receiptString); - - //Checking whether the request body is in JSON format - if (!(receiptJSON instanceof JSONObject)) { - log.error(ErrorConstants.NOT_JSON_OBJECT_ERROR); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.NOT_JSON_OBJECT_ERROR); - } - - //Checking whether the consent status is valid - if (!consentResource.getCurrentStatus().equals(ConsentExtensionConstants.AWAITING_AUTH_STATUS) && - !consentResource.getCurrentStatus().equals(ConsentExtensionConstants.AUTHORIZED_STATUS)) { - log.error(ErrorConstants.STATE_INVALID_ERROR); - //Currently throwing error as 400 response. Developer also have the option of appending a field IS_ERROR - // to the jsonObject and showing it to the user in the webapp. If so, the IS_ERROR have to be checked in - // any later steps. - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.STATE_INVALID_ERROR); - } - - JSONArray consentDataJSON = new JSONArray(); - JSONObject receipt = (JSONObject) receiptJSON; - JSONObject data = (JSONObject) receipt.get(ConsentExtensionConstants.DATA); - - //Adding Expiration Date Time - if (data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE) != null) { - - if (!ConsentRetrievalUtil - .validateExpiryDateTime(data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE))) { - log.error(ErrorConstants.CONSENT_EXPIRED); - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.CONSENT_EXPIRED); - } - - String expiry = data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE); - JSONArray expiryArray = new JSONArray(); - expiryArray.add(expiry); - - JSONObject jsonElementExpiry = new JSONObject(); - jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.EXPIRATION_DATE_TITLE); - jsonElementExpiry.appendField(ConsentExtensionConstants.DATA_SIMPLE, expiryArray); - consentDataJSON.add(jsonElementExpiry); - } else { - JSONArray expiryArray = new JSONArray(); - expiryArray.add(ConsentExtensionConstants.OPEN_ENDED_AUTHORIZATION); - - JSONObject jsonElementExpiry = new JSONObject(); - jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.EXPIRATION_DATE_TITLE); - jsonElementExpiry.appendField(ConsentExtensionConstants.DATA_SIMPLE, expiryArray); - consentDataJSON.add(jsonElementExpiry); - } - - //Adding Debtor Account - if (data.get(ConsentExtensionConstants.DEBTOR_ACC) != null) { - JSONObject debtorAccount = (JSONObject) data.get(ConsentExtensionConstants.DEBTOR_ACC); - JSONArray debtorAccountArray = new JSONArray(); - //Adding Debtor Account Scheme Name - if (debtorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME) != null) { - debtorAccountArray.add(ConsentExtensionConstants.SCHEME_NAME_TITLE + " : " + - debtorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME)); - } - //Adding Debtor Account Identification - if (debtorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION) != null) { - debtorAccountArray.add(ConsentExtensionConstants.IDENTIFICATION_TITLE + " : " + - debtorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION)); - } - //Adding Debtor Account Name - if (debtorAccount.getAsString(ConsentExtensionConstants.NAME) != null) { - debtorAccountArray.add(ConsentExtensionConstants.NAME_TITLE + " : " + - debtorAccount.getAsString(ConsentExtensionConstants.NAME)); - } - //Adding Debtor Account Secondary Identification - if (debtorAccount.getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION) != null) { - debtorAccountArray.add(ConsentExtensionConstants.SECONDARY_IDENTIFICATION_TITLE + " : " + - debtorAccount.getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION)); - } - - JSONObject jsonElementDebtor = new JSONObject(); - jsonElementDebtor.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.DEBTOR_ACC_TITLE); - jsonElementDebtor.appendField(ConsentExtensionConstants.DATA_SIMPLE, debtorAccountArray); - consentDataJSON.add(jsonElementDebtor); - } - - if (log.isDebugEnabled()) { - log.debug("Returned consent data to get the PSU consent " + consentDataJSON); - } - - return consentDataJSON; - } catch (ParseException e) { - log.error("Exception occurred while getting consent data. Caused by : ", e); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.CONSENT_RETRIEVAL_ERROR); - } - } - -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/ConsentRetrievalHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/ConsentRetrievalHandler.java deleted file mode 100644 index 2cb0375b..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/ConsentRetrievalHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval; - - -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; - - -/** - * Interface to handle Consent data retrieval for Authorize. - */ -public interface ConsentRetrievalHandler { - - /** - * Abstract method defined to retrieve the consent related data in the authorization flow to send them to the - * consent page to get PSU consent. - * - * @param consentResource Consent Resource parameter containing consent related information retrieved from database - * @return - * @throws ConsentException - */ - JSONArray getConsentDataSet(ConsentResource consentResource) throws ConsentException; - -} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/PaymentConsentRetrievalHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/PaymentConsentRetrievalHandler.java deleted file mode 100644 index cff4e09e..00000000 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/impl/handler/retrieval/PaymentConsentRetrievalHandler.java +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval; - -import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; -import com.wso2.openbanking.accelerator.common.util.ErrorConstants; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.utils.ConsentRetrievalUtil; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionUtils; -import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; -import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; -import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; -import net.minidev.json.parser.ParseException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Class to handle Payment Consent data retrieval for Authorize. - */ -public class PaymentConsentRetrievalHandler implements ConsentRetrievalHandler { - - private static final Log log = LogFactory.getLog(PaymentConsentRetrievalHandler.class); - - - /** - * Method defined to retrieve the Payment consent related data in the authorization flow to send them to the. - * consent page to get PSU consent - * - * @param consentResource Consent Resource parameter containing consent related information retrieved from database - * @return - * @throws ConsentException - */ - @Override - public JSONArray getConsentDataSet(ConsentResource consentResource) { - - try { - String receiptString = consentResource.getReceipt(); - Object receiptJSON = new JSONParser(JSONParser.MODE_PERMISSIVE).parse(receiptString); - - //Checking whether the request body is in JSON format - if (!(receiptJSON instanceof JSONObject)) { - log.error(ErrorConstants.NOT_JSON_OBJECT_ERROR); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.NOT_JSON_OBJECT_ERROR); - } - - //Checking whether the consent status is valid - if (!consentResource.getCurrentStatus().equals(ConsentExtensionConstants.AWAITING_AUTH_STATUS)) { - log.error(ErrorConstants.STATE_INVALID_ERROR); - //Currently throwing error as 400 response. Developer also have the option of appending a field IS_ERROR - // to the jsonObject and showing it to the user in the webapp. If so, the IS_ERROR have to be checked in - // any later steps. - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.STATE_INVALID_ERROR); - } - - JSONArray consentDataJSON = new JSONArray(); - JSONObject receipt = (JSONObject) receiptJSON; - JSONObject data = (JSONObject) receipt.get(ConsentExtensionConstants.DATA); - JSONObject initiation = (JSONObject) data.get(ConsentExtensionConstants.INITIATION); - - // Rejecting consent if cut off time is elapsed and the policy is REJECT - // Updating the consent status to "Reject" if the above condition is true - if (ConsentExtensionUtils.shouldSubmissionRequestBeRejected(ConsentExtensionUtils - .convertToISO8601(consentResource.getCreatedTime()))) { - boolean success = ConsentServiceUtil.getConsentService() - .revokeConsent(consentResource.getConsentID(), ConsentExtensionConstants.REJECTED_STATUS); - if (!success) { - log.error(ErrorConstants.AUTH_TOKEN_REVOKE_ERROR); - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, - ErrorConstants.AUTH_TOKEN_REVOKE_ERROR); - } - log.error(ErrorConstants.AUTH_CUT_OFF_DATE_ELAPSED); - throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.AUTH_CUT_OFF_DATE_ELAPSED); - } - - consentDataJSON = populateSinglePaymentData(initiation, consentDataJSON); - //Adding Debtor Account - ConsentRetrievalUtil.populateDebtorAccount(initiation, consentDataJSON); - - //Adding Creditor Account - ConsentRetrievalUtil.populateCreditorAccount(initiation, consentDataJSON); - - return consentDataJSON; - } catch (ParseException | ConsentManagementException e) { - throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, ErrorConstants.CONSENT_RETRIEVAL_ERROR); - } - } - - /** - * Populate Domestic and international Payment Details. - * - * @param data Initiation request from th request - * @param consentDataJSON Consent information - */ - private static JSONArray populateSinglePaymentData(JSONObject data, JSONArray consentDataJSON) { - - JSONArray paymentTypeArray = new JSONArray(); - JSONObject jsonElementPaymentType = new JSONObject(); - - if (data.containsKey(ConsentExtensionConstants.CURRENCY_OF_TRANSFER)) { - //For International Payments - //Adding Payment Type - paymentTypeArray.add(ConsentExtensionConstants.INTERNATIONAL_PAYMENTS); - - jsonElementPaymentType.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.PAYMENT_TYPE_TITLE); - jsonElementPaymentType.appendField(ConsentExtensionConstants.DATA_SIMPLE, paymentTypeArray); - consentDataJSON.add(jsonElementPaymentType); - - //Adding Currency Of Transfer - JSONArray currencyTransferArray = new JSONArray(); - currencyTransferArray.add(data.getAsString(ConsentExtensionConstants.CURRENCY_OF_TRANSFER)); - - JSONObject jsonElementCurTransfer = new JSONObject(); - jsonElementCurTransfer.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.CURRENCY_OF_TRANSFER_TITLE); - jsonElementCurTransfer.appendField(ConsentExtensionConstants.DATA_SIMPLE, currencyTransferArray); - consentDataJSON.add(jsonElementCurTransfer); - } else { - //Adding Payment Type - paymentTypeArray.add(ConsentExtensionConstants.DOMESTIC_PAYMENTS); - - jsonElementPaymentType.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.PAYMENT_TYPE_TITLE); - jsonElementPaymentType.appendField(ConsentExtensionConstants.DATA_SIMPLE, paymentTypeArray); - consentDataJSON.add(jsonElementPaymentType); - } - - //Adding InstructionIdentification - JSONArray identificationArray = new JSONArray(); - identificationArray.add(data.getAsString(ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION)); - - JSONObject jsonElementIdentification = new JSONObject(); - jsonElementIdentification.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION_TITLE); - jsonElementIdentification.appendField(ConsentExtensionConstants.DATA_SIMPLE, identificationArray); - consentDataJSON.add(jsonElementIdentification); - - //Adding EndToEndIdentification - JSONArray endToEndIdentificationArray = new JSONArray(); - endToEndIdentificationArray - .add(data.getAsString(ConsentExtensionConstants.END_TO_END_IDENTIFICATION)); - - JSONObject jsonElementEndToEndIdentification = new JSONObject(); - jsonElementEndToEndIdentification.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.END_TO_END_IDENTIFICATION_TITLE); - jsonElementEndToEndIdentification.appendField(ConsentExtensionConstants.DATA_SIMPLE, - endToEndIdentificationArray); - consentDataJSON.add(jsonElementEndToEndIdentification); - - //Adding InstructedAmount - JSONObject instructedAmount = (JSONObject) data.get(ConsentExtensionConstants.INSTRUCTED_AMOUNT); - JSONArray instructedAmountArray = new JSONArray(); - - if (instructedAmount.getAsString(ConsentExtensionConstants.AMOUNT_TITLE) != null) { - instructedAmountArray.add(ConsentExtensionConstants.AMOUNT_TITLE + " : " + - instructedAmount.getAsString(ConsentExtensionConstants.AMOUNT)); - } - - if (instructedAmount.getAsString(ConsentExtensionConstants.CURRENCY) != null) { - instructedAmountArray.add(ConsentExtensionConstants.CURRENCY_TITLE + " : " + - instructedAmount.getAsString(ConsentExtensionConstants.CURRENCY)); - } - - JSONObject jsonElementInstructedAmount = new JSONObject(); - jsonElementInstructedAmount.appendField(ConsentExtensionConstants.TITLE, - ConsentExtensionConstants.INSTRUCTED_AMOUNT_TITLE); - jsonElementInstructedAmount.appendField(ConsentExtensionConstants.DATA_SIMPLE, instructedAmountArray); - consentDataJSON.add(jsonElementInstructedAmount); - - return consentDataJSON; - } - -} - diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/utils/ConsentRetrievalUtil.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/utils/ConsentRetrievalUtil.java index 8bc85ee1..f0cc17b4 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/utils/ConsentRetrievalUtil.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/utils/ConsentRetrievalUtil.java @@ -6,7 +6,7 @@ * in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -16,7 +16,6 @@ * under the License. */ - package com.wso2.openbanking.accelerator.consent.extensions.authorize.utils; @@ -24,6 +23,7 @@ import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.parser.JSONParser; @@ -47,8 +47,8 @@ public class ConsentRetrievalUtil { /** * Method to extract request object from query params. * - * @param spQueryParams - * @return + * @param spQueryParams Query params + * @return requestObject */ public static String extractRequestObject(String spQueryParams) { @@ -71,14 +71,13 @@ public static String extractRequestObject(String spQueryParams) { /** * Method to validate the request object and extract consent ID. * - * @param requestObject - * @return + * @param requestObject Request object + * @return consentId */ public static String extractConsentId(String requestObject) { String consentId = null; try { - // validate request object and get the payload String requestObjectPayload; String[] jwtTokenValues = requestObject.split("\\."); @@ -146,7 +145,6 @@ public static boolean validateExpiryDateTime(String expiryDate) throws ConsentEx } } - /** * Method to add debtor account details to consent data to send it to the consent page. * @@ -154,7 +152,6 @@ public static boolean validateExpiryDateTime(String expiryDate) throws ConsentEx * @param consentDataJSON Consent information object */ public static void populateDebtorAccount(JSONObject initiation, JSONArray consentDataJSON) { - if (initiation.get(ConsentExtensionConstants.DEBTOR_ACC) != null) { JSONObject debtorAccount = (JSONObject) initiation.get(ConsentExtensionConstants.DEBTOR_ACC); JSONArray debtorAccountArray = new JSONArray(); @@ -187,19 +184,19 @@ public static void populateDebtorAccount(JSONObject initiation, JSONArray consen JSONObject jsonElementDebtor = new JSONObject(); jsonElementDebtor.appendField(ConsentExtensionConstants.TITLE, ConsentExtensionConstants.DEBTOR_ACC_TITLE); - jsonElementDebtor.appendField(ConsentExtensionConstants.DATA_SIMPLE, debtorAccountArray); + jsonElementDebtor.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), debtorAccountArray); consentDataJSON.add(jsonElementDebtor); } } + /** * Method to add debtor account details to consent data to send it to the consent page. * - * @param initiation - * @param consentDataJSON + * @param initiation Initiation object from the request + * @param consentDataJSON Consent information object */ public static void populateCreditorAccount(JSONObject initiation, JSONArray consentDataJSON) { - if (initiation.get(ConsentExtensionConstants.CREDITOR_ACC) != null) { JSONObject creditorAccount = (JSONObject) initiation.get(ConsentExtensionConstants.CREDITOR_ACC); JSONArray creditorAccountArray = new JSONArray(); @@ -227,11 +224,13 @@ public static void populateCreditorAccount(JSONObject initiation, JSONArray cons JSONObject jsonElementCreditor = new JSONObject(); jsonElementCreditor.appendField(ConsentExtensionConstants.TITLE, ConsentExtensionConstants.CREDITOR_ACC_TITLE); - jsonElementCreditor.appendField(ConsentExtensionConstants.DATA_SIMPLE, creditorAccountArray); + jsonElementCreditor.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + creditorAccountArray); consentDataJSON.add(jsonElementCreditor); } } + /** * Method to append Dummy data for Account ID. Ideally should be separate step calling accounts service * @@ -256,4 +255,446 @@ public static JSONArray appendDummyAccountID() { return accountsJSON; } + + /** + * Method that consists the implementation for the validation of payload and the consent, + * this method also invokes the relevant methods to populate data for each flow. + * + * @param consentResource Consent Resource parameter containing consent related information retrieved + * from database. + * @return ConsentDataJson array + */ + public static JSONArray getConsentData(ConsentResource consentResource) throws ConsentException { + + JSONArray consentDataJSON = new JSONArray(); + try { + + String receiptString = consentResource.getReceipt(); + Object receiptJSON = new JSONParser(JSONParser.MODE_PERMISSIVE).parse(receiptString); + + // Checking whether the request body is in JSON format + if (!(receiptJSON instanceof JSONObject)) { + log.error(ErrorConstants.NOT_JSON_OBJECT_ERROR); + throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, + ErrorConstants.NOT_JSON_OBJECT_ERROR); + } + + if (!ConsentExtensionConstants.AWAITING_AUTH_STATUS.equals(consentResource.getCurrentStatus())) { + log.error(ErrorConstants.STATE_INVALID_ERROR); + // Currently throwing an error as a 400 response. + // Developers have the option of appending a field IS_ERROR to the jsonObject + // and showing it to the user in the webapp.If so,the IS_ERROR has to be checked in any later steps. + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.STATE_INVALID_ERROR); + } + + JSONObject receipt = (JSONObject) receiptJSON; + + // Checks if 'data' object is present in the receipt + if (receipt.containsKey(ConsentExtensionConstants.DATA)) { + JSONObject data = (JSONObject) receipt.get(ConsentExtensionConstants.DATA); + + String type = consentResource.getConsentType(); + switch (type) { + case ConsentExtensionConstants.ACCOUNTS: + populateAccountData(data, consentDataJSON); + break; + case ConsentExtensionConstants.PAYMENTS: + populatePaymentData(data, consentDataJSON); + break; + case ConsentExtensionConstants.FUNDSCONFIRMATIONS: + populateCofData(data, consentDataJSON); + break; + case ConsentExtensionConstants.VRP: + populateVRPData(data, consentDataJSON); + break; + default: + break; + } + } else { + log.error(ErrorConstants.DATA_OBJECT_MISSING_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.DATA_OBJECT_MISSING_ERROR); + } + } catch (ParseException e) { + log.error(ErrorConstants.CONSENT_RETRIEVAL_ERROR, e); + throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, + ErrorConstants.CONSENT_RETRIEVAL_ERROR); + } + return consentDataJSON; + } + + /** + * Populate Domestic and international Payment Details. + * + * @param data data request from the request + * @param consentDataJSON Consent information + */ + private static void populatePaymentData(JSONObject data, JSONArray consentDataJSON) { + + JSONArray paymentTypeArray = new JSONArray(); + JSONObject jsonElementPaymentType = new JSONObject(); + + if (data.containsKey(ConsentExtensionConstants.INITIATION)) { + JSONObject initiation = (JSONObject) data.get(ConsentExtensionConstants.INITIATION); + + if (initiation.containsKey(ConsentExtensionConstants.CURRENCY_OF_TRANSFER)) { + //For International Payments + //Adding Payment Type + paymentTypeArray.add(ConsentExtensionConstants.INTERNATIONAL_PAYMENTS); + + jsonElementPaymentType.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.PAYMENT_TYPE_TITLE); + jsonElementPaymentType.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + paymentTypeArray); + consentDataJSON.add(jsonElementPaymentType); + + //Adding Currency Of Transfer + JSONArray currencyTransferArray = new JSONArray(); + currencyTransferArray.add(initiation.getAsString(ConsentExtensionConstants.CURRENCY_OF_TRANSFER)); + + JSONObject jsonElementCurTransfer = new JSONObject(); + jsonElementCurTransfer.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CURRENCY_OF_TRANSFER_TITLE); + jsonElementCurTransfer.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + currencyTransferArray); + consentDataJSON.add(jsonElementCurTransfer); + } else { + //Adding Payment Type + paymentTypeArray.add(ConsentExtensionConstants.DOMESTIC_PAYMENTS); + + jsonElementPaymentType.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.PAYMENT_TYPE_TITLE); + jsonElementPaymentType.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + paymentTypeArray); + consentDataJSON.add(jsonElementPaymentType); + } + + //Adding InstructionIdentification + JSONArray identificationArray = new JSONArray(); + identificationArray.add(initiation.getAsString(ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION)); + + JSONObject jsonElementIdentification = new JSONObject(); + jsonElementIdentification.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION_TITLE); + jsonElementIdentification.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + identificationArray); + consentDataJSON.add(jsonElementIdentification); + + //Adding EndToEndIdentification + JSONArray endToEndIdentificationArray = new JSONArray(); + endToEndIdentificationArray + .add(initiation.getAsString(ConsentExtensionConstants.END_TO_END_IDENTIFICATION)); + + JSONObject jsonElementEndToEndIdentification = new JSONObject(); + jsonElementEndToEndIdentification.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.END_TO_END_IDENTIFICATION_TITLE); + jsonElementEndToEndIdentification.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + endToEndIdentificationArray); + consentDataJSON.add(jsonElementEndToEndIdentification); + + //Adding InstructedAmount + JSONObject instructedAmount = (JSONObject) initiation.get(ConsentExtensionConstants.INSTRUCTED_AMOUNT); + JSONArray instructedAmountArray = new JSONArray(); + + if (instructedAmount.getAsString(ConsentExtensionConstants.AMOUNT_TITLE) != null) { + instructedAmountArray.add(ConsentExtensionConstants.AMOUNT_TITLE + " : " + + instructedAmount.getAsString(ConsentExtensionConstants.AMOUNT)); + } + + if (instructedAmount.getAsString(ConsentExtensionConstants.CURRENCY) != null) { + instructedAmountArray.add(ConsentExtensionConstants.CURRENCY_TITLE + " : " + + instructedAmount.getAsString(ConsentExtensionConstants.CURRENCY)); + } + + JSONObject jsonElementInstructedAmount = new JSONObject(); + jsonElementInstructedAmount.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.INSTRUCTED_AMOUNT_TITLE); + jsonElementInstructedAmount.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + instructedAmountArray); + consentDataJSON.add(jsonElementInstructedAmount); + + // Adding Debtor Account + populateDebtorAccount(initiation, consentDataJSON); + // Adding Creditor Account + populateCreditorAccount(initiation, consentDataJSON); + + } + } + + /** + * Populate account Details. + * + * @param data data request from the request + * @param consentDataJSON Consent information + */ + private static void populateAccountData(JSONObject data, JSONArray consentDataJSON) { + + //Adding Permissions + JSONArray permissions = (JSONArray) data.get(ConsentExtensionConstants.PERMISSIONS); + if (permissions != null) { + JSONObject jsonElementPermissions = new JSONObject(); + jsonElementPermissions.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.PERMISSIONS); + jsonElementPermissions.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + permissions); + consentDataJSON.add(jsonElementPermissions); + } + + //Adding Expiration Date Time + String expirationDate = data.getAsString(ConsentExtensionConstants.EXPIRATION_DATE); + if (expirationDate != null) { + if (!ConsentRetrievalUtil.validateExpiryDateTime(expirationDate)) { + log.error(ErrorConstants.CONSENT_EXPIRED); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.CONSENT_EXPIRED); + } + JSONArray expiryArray = new JSONArray(); + expiryArray.add(expirationDate); + + JSONObject jsonElementExpiry = new JSONObject(); + jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.EXPIRATION_DATE_TITLE); + jsonElementExpiry.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + expiryArray); + consentDataJSON.add(jsonElementExpiry); + } + + //Adding Transaction From Date Time + String fromDateTime = data.getAsString(ConsentExtensionConstants.TRANSACTION_FROM_DATE); + if (fromDateTime != null) { + JSONArray fromDateTimeArray = new JSONArray(); + fromDateTimeArray.add(fromDateTime); + + JSONObject jsonElementFromDateTime = new JSONObject(); + jsonElementFromDateTime.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.TRANSACTION_FROM_DATE_TITLE); + jsonElementFromDateTime.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + fromDateTimeArray); + consentDataJSON.add(jsonElementFromDateTime); + } + + //Adding Transaction To Date Time + String toDateTime = data.getAsString(ConsentExtensionConstants.TRANSACTION_TO_DATE); + if (toDateTime != null) { + JSONArray toDateTimeArray = new JSONArray(); + toDateTimeArray.add(toDateTime); + + JSONObject jsonElementToDateTime = new JSONObject(); + jsonElementToDateTime.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.TRANSACTION_TO_DATE_TITLE); + jsonElementToDateTime.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + toDateTimeArray); + consentDataJSON.add(jsonElementToDateTime); + } + } + + /** + * Populate funds confirmation Details. + * + * @param initiation data from the request + * @param consentDataJSON Consent information + */ + private static void populateCofData(JSONObject initiation, JSONArray consentDataJSON) { + + //Adding Expiration Date Time + if (initiation.getAsString(ConsentExtensionConstants.EXPIRATION_DATE) != null) { + + if (!ConsentRetrievalUtil + .validateExpiryDateTime(initiation.getAsString(ConsentExtensionConstants.EXPIRATION_DATE))) { + log.error(ErrorConstants.CONSENT_EXPIRED); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.CONSENT_EXPIRED); + } + + String expiry = initiation.getAsString(ConsentExtensionConstants.EXPIRATION_DATE); + JSONArray expiryArray = new JSONArray(); + expiryArray.add(expiry); + + JSONObject jsonElementExpiry = new JSONObject(); + jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.EXPIRATION_DATE_TITLE); + jsonElementExpiry.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), expiryArray); + consentDataJSON.add(jsonElementExpiry); + } else { + JSONArray expiryArray = new JSONArray(); + expiryArray.add(ConsentExtensionConstants.OPEN_ENDED_AUTHORIZATION); + + JSONObject jsonElementExpiry = new JSONObject(); + jsonElementExpiry.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.EXPIRATION_DATE_TITLE); + jsonElementExpiry.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), expiryArray); + consentDataJSON.add(jsonElementExpiry); + } + + if (initiation.get(ConsentExtensionConstants.DEBTOR_ACC) != null) { + //Adding Debtor Account + populateDebtorAccount(initiation, consentDataJSON); + } + } + + /** + * Populate VRP Details. + * + * @param data Control Parameters from the request + * @param consentDataJSON Consent information object + */ + private static void populateVRPData(JSONObject data, JSONArray consentDataJSON) { + + if (!data.containsKey(ConsentExtensionConstants.CONTROL_PARAMETERS)) { + log.error(ErrorConstants.CONTROL_PARAMETERS_MISSING_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.CONTROL_PARAMETERS_MISSING_ERROR); + } else { + + JSONObject controlParameters = (JSONObject) data. + get(ConsentExtensionConstants.CONTROL_PARAMETERS); + + //Adding Payment Type + JSONArray paymentTypeArray = new JSONArray(); + JSONObject jsonElementPaymentType = new JSONObject(); + paymentTypeArray.add(ConsentExtensionConstants.DOMESTIC_VRP); + jsonElementPaymentType.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.PAYMENT_TYPE_TITLE); + jsonElementPaymentType.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + paymentTypeArray); + consentDataJSON.add(jsonElementPaymentType); + + String validToDateTime = controlParameters.getAsString(ConsentExtensionConstants.VALID_TO_DATE_TIME); + if (validToDateTime != null) { + // Constructing jsonElementValidToDataTime + JSONObject jsonElementValidToDateTime = new JSONObject(); + jsonElementValidToDateTime.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_VALID_TO_DATE_TITLE); + JSONArray dateControlParameterArray = new JSONArray(); + dateControlParameterArray.add((controlParameters). + get(ConsentExtensionConstants.VALID_TO_DATE_TIME)); + jsonElementValidToDateTime.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + dateControlParameterArray); + + consentDataJSON.add(jsonElementValidToDateTime); + } + + String validFromDateTime = controlParameters.getAsString + (ConsentExtensionConstants.VALID_FROM_DATE_TIME); + if (validFromDateTime != null) { + // Constructing jsonElementValidFromDataTime + JSONObject jsonElementValidFromDateTime = new JSONObject(); + jsonElementValidFromDateTime.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_VALID_FROM_DATE_TITLE); + JSONArray dateTimeControlParameterArray = new JSONArray(); + dateTimeControlParameterArray.add((controlParameters). + get(ConsentExtensionConstants.VALID_FROM_DATE_TIME)); + jsonElementValidFromDateTime.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + dateTimeControlParameterArray); + consentDataJSON.add(jsonElementValidFromDateTime); + } + + Object maxAmount = controlParameters.get(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT); + + if (maxAmount instanceof JSONObject) { + JSONObject jsonElementControlParameter = new JSONObject(); + jsonElementControlParameter.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_MAX_INDIVIDUAL_AMOUNT_TITLE); + JSONArray controlParameterArray = new JSONArray(); + + JSONObject maximumIndividualAmount = (JSONObject) maxAmount; + + String formattedAmount = String.format("%s %s", + maximumIndividualAmount.getAsString(ConsentExtensionConstants.CURRENCY), + maximumIndividualAmount.getAsString(ConsentExtensionConstants.AMOUNT)); + controlParameterArray.add(formattedAmount); + jsonElementControlParameter.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + controlParameterArray); + + consentDataJSON.add(jsonElementControlParameter); + } else { + log.error(ErrorConstants.MAX_AMOUNT_NOT_JSON_OBJECT_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.MAX_AMOUNT_NOT_JSON_OBJECT_ERROR); + } + + Object periodicLimit = controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + + if (periodicLimit instanceof JSONArray) { + JSONArray periodicLimitsArrays = (JSONArray) periodicLimit; + + for (Object periodicLimitObject : periodicLimitsArrays) { + if (periodicLimitObject instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) periodicLimitObject; + + Object periodAlignmentObject = jsonObject.get(ConsentExtensionConstants.PERIOD_ALIGNMENT); + + if (periodAlignmentObject instanceof String) { + // Constructing jsonElementPeriodAlignment + JSONObject jsonElementPeriodAlignment = new JSONObject(); + jsonElementPeriodAlignment.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_PERIOD_ALIGNMENT_TITLE); + + JSONArray periodAlignmentArray = new JSONArray(); + periodAlignmentArray.add(periodAlignmentObject); + + jsonElementPeriodAlignment.appendField(StringUtils. + lowerCase(ConsentExtensionConstants.DATA), periodAlignmentArray); + consentDataJSON.add(jsonElementPeriodAlignment); + } else { + log.error(ErrorConstants.PERIOD_ALIGNMENT_NOT_STRING_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.PERIOD_ALIGNMENT_NOT_STRING_ERROR); + } + + Object periodTypeObject = jsonObject.get(ConsentExtensionConstants.PERIOD_TYPE); + + if (periodTypeObject instanceof String) { + + JSONObject jsonElementPeriodType = new JSONObject(); + jsonElementPeriodType.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_PERIOD_TYPE_TITLE); + + JSONArray periodTypeArray = new JSONArray(); + periodTypeArray.add(periodTypeObject); + + jsonElementPeriodType.appendField(StringUtils.lowerCase(ConsentExtensionConstants.DATA), + periodTypeArray); + + consentDataJSON.add(jsonElementPeriodType); + + } else { + log.error(ErrorConstants.PERIOD_TYPE_NOT_STRING_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.PERIOD_TYPE_NOT_STRING_ERROR); + } + // Constructing jsonElementPeriodicLimitsAmountCurrency - periodicLimits amount and currency + Object amount = jsonObject.get(ConsentExtensionConstants.AMOUNT); + Object currency = jsonObject.get(ConsentExtensionConstants.CURRENCY); + + if (amount instanceof String && currency instanceof String) { + String periodTypeString = (String) periodTypeObject; + + JSONObject jsonElementPeriodicLimitsAmountCurrency = new JSONObject(); + jsonElementPeriodicLimitsAmountCurrency.appendField(ConsentExtensionConstants.TITLE, + ConsentExtensionConstants.CONTROL_PARAMETER_AMOUNT_TITLE + + periodTypeString); + + JSONArray periodicLimitsArray = new JSONArray(); + + String amountString = (String) amount; + String currencyString = (String) currency; + + String formattedPeriodicAmount = String.format("%s %s", currencyString, amountString); + periodicLimitsArray.add(formattedPeriodicAmount); + + jsonElementPeriodicLimitsAmountCurrency.appendField(StringUtils. + lowerCase(ConsentExtensionConstants.DATA), periodicLimitsArray); + consentDataJSON.add(jsonElementPeriodicLimitsAmountCurrency); + + } else { + log.error(ErrorConstants.NOT_STRING_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, + ErrorConstants.NOT_STRING_ERROR); + } + } + } + } else { + log.error(ErrorConstants.NOT_JSON_ARRAY_ERROR); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.NOT_JSON_ARRAY_ERROR); + } + } + } } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/OBDefaultAuthServletImpl.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/OBDefaultAuthServletImpl.java index e7679374..6e33d788 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/OBDefaultAuthServletImpl.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/OBDefaultAuthServletImpl.java @@ -53,6 +53,8 @@ public Map updateRequestAttribute(HttpServletRequest request, JS return Utils.populatePaymentsData(request, dataSet); case ConsentExtensionConstants.FUNDSCONFIRMATIONS: return Utils.populateCoFData(request, dataSet); + case ConsentExtensionConstants.VRP: + return Utils.populateVRPDataRetrieval(request, dataSet); default: return new HashMap<>(); } @@ -72,11 +74,6 @@ public Map updateConsentData(HttpServletRequest request) { String[] accounts = request.getParameter("accounts[]").split(":"); returnMaps.put("accountIds", new JSONArray(accounts)); - returnMaps.put(ConsentExtensionConstants.PAYMENT_ACCOUNT, - request.getParameter(ConsentExtensionConstants.PAYMENT_ACCOUNT)); - returnMaps.put(ConsentExtensionConstants.COF_ACCOUNT, - request.getParameter(ConsentExtensionConstants.COF_ACCOUNT)); - return returnMaps; } @@ -89,7 +86,8 @@ public Map updateConsentMetaData(HttpServletRequest request) { @Override public String getJSPPath() { - if (jspPath.equalsIgnoreCase(ConsentExtensionConstants.ACCOUNTS)) { + if (jspPath.equalsIgnoreCase(ConsentExtensionConstants.ACCOUNTS) || + jspPath.equalsIgnoreCase(ConsentExtensionConstants.VRP)) { return "/ob_default.jsp"; } else { return "/default_displayconsent.jsp"; diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/util/Utils.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/util/Utils.java index 2e025dfb..73c6a91b 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/util/Utils.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/util/Utils.java @@ -47,9 +47,9 @@ public class Utils { * To get the property value for the given key from the ResourceBundle. * Retrieve the value of property entry for key, return key if a value is not found for key * - * @param resourceBundle - * @param key - * @return + * @param resourceBundle ResourceBundle + * @param key Key + * @return Value of the property entry for key */ public static String i18n(ResourceBundle resourceBundle, String key) { @@ -66,8 +66,8 @@ public static String i18n(ResourceBundle resourceBundle, String key) { /** * Split claims based on a deliminator and create map of claimID and displayName. * - * @param requestedClaimList - * @return + * @param requestedClaimList Requested claim list + * @return List of claims */ public static List> splitClaims(String[] requestedClaimList) { @@ -88,9 +88,9 @@ public static List> splitClaims(String[] requestedClaimList) /** * Method to populate accounts data to be sent to consent page. * - * @param request - * @param dataSet - * @return + * @param request HttpServletRequest + * @param dataSet Request payload JSONObject + * @return Map of Accounts data */ public static Map populateAccountsData(HttpServletRequest request, JSONObject dataSet) { @@ -103,7 +103,7 @@ public static Map populateAccountsData(HttpServletRequest reques for (int requestedDataIndex = 0; requestedDataIndex < dataRequestedJsonArray.length(); requestedDataIndex++) { JSONObject dataObj = dataRequestedJsonArray.getJSONObject(requestedDataIndex); String title = dataObj.getString(ConsentExtensionConstants.TITLE); - JSONArray dataArray = dataObj.getJSONArray(ConsentExtensionConstants.DATA_SIMPLE); + JSONArray dataArray = dataObj.getJSONArray(StringUtils.lowerCase(ConsentExtensionConstants.DATA)); ArrayList listData = new ArrayList<>(); for (int dataIndex = 0; dataIndex < dataArray.length(); dataIndex++) { @@ -124,9 +124,9 @@ public static Map populateAccountsData(HttpServletRequest reques /** * Method to populate payments data to be sent to consent page. * - * @param request - * @param dataSet - * @return + * @param request HttpServletRequest + * @param dataSet Request payload JSONObject + * @return Map of Payments data */ public static Map populatePaymentsData(HttpServletRequest request, JSONObject dataSet) { @@ -140,7 +140,7 @@ public static Map populatePaymentsData(HttpServletRequest reques for (int requestedDataIndex = 0; requestedDataIndex < dataRequestedJsonArray.length(); requestedDataIndex++) { JSONObject dataObj = dataRequestedJsonArray.getJSONObject(requestedDataIndex); String title = dataObj.getString(ConsentExtensionConstants.TITLE); - JSONArray dataArray = dataObj.getJSONArray(ConsentExtensionConstants.DATA_SIMPLE); + JSONArray dataArray = dataObj.getJSONArray(StringUtils.lowerCase(ConsentExtensionConstants.DATA)); ArrayList listData = new ArrayList<>(); for (int dataIndex = 0; dataIndex < dataArray.length(); dataIndex++) { @@ -167,9 +167,9 @@ public static Map populatePaymentsData(HttpServletRequest reques /** * Method to populate Confirmation of Funds data to be sent to consent page. * - * @param httpServletRequest - * @param dataSet - * @return + * @param httpServletRequest HttpServletRequest + * @param dataSet Request payload JSONObject + * @return Map of Confirmation of Funds data */ public static Map populateCoFData(HttpServletRequest httpServletRequest, JSONObject dataSet) { @@ -182,7 +182,7 @@ public static Map populateCoFData(HttpServletRequest httpServlet for (int requestedDataIndex = 0; requestedDataIndex < dataRequestedJsonArray.length(); requestedDataIndex++) { JSONObject dataObj = dataRequestedJsonArray.getJSONObject(requestedDataIndex); String title = dataObj.getString(ConsentExtensionConstants.TITLE); - JSONArray dataArray = dataObj.getJSONArray(ConsentExtensionConstants.DATA_SIMPLE); + JSONArray dataArray = dataObj.getJSONArray(StringUtils.lowerCase(ConsentExtensionConstants.DATA)); ArrayList listData = new ArrayList<>(); for (int dataIndex = 0; dataIndex < dataArray.length(); dataIndex++) { @@ -208,7 +208,7 @@ public static Map populateCoFData(HttpServletRequest httpServlet * Method to retrieve debtor account from consent data object. * * @param consentDataObject Object containing consent related data - * @return + * @return Debtor account */ public static String getDebtorAccFromConsentData(JSONArray consentDataObject) { @@ -217,7 +217,7 @@ public static String getDebtorAccFromConsentData(JSONArray consentDataObject) { String title = dataObj.getString(ConsentExtensionConstants.TITLE); if (ConsentExtensionConstants.DEBTOR_ACC_TITLE.equals(title)) { - JSONArray dataArray = dataObj.getJSONArray(ConsentExtensionConstants.DATA_SIMPLE); + JSONArray dataArray = dataObj.getJSONArray(StringUtils.lowerCase(ConsentExtensionConstants.DATA)); for (int dataIndex = 0; dataIndex < dataArray.length(); dataIndex++) { String data = (String) dataArray.get(dataIndex); @@ -250,4 +250,47 @@ private static List> addAccList (JSONObject dataSet) { return accountData; } + /** + * Method to populate vrp data to be sent to consent page. + * + * @param request HttpServletRequest + * @param dataSet Request payload JSONObject + * @return Map of VRP data + */ + public static Map populateVRPDataRetrieval(HttpServletRequest request, JSONObject dataSet) { + + String selectedAccount = null; + Map returnMaps = new HashMap<>(); + + // Populates "consentDataArray" with the scope information in a readable format + JSONArray consentDataArray = dataSet.getJSONArray(ConsentExtensionConstants.CONSENT_DATA); + Map> dataRequested = new LinkedHashMap<>(); + + for (int requestedDataIndex = 0; requestedDataIndex < consentDataArray.length(); requestedDataIndex++) { + JSONObject dataObj = consentDataArray.getJSONObject(requestedDataIndex); + String title = dataObj.getString(ConsentExtensionConstants.TITLE); + JSONArray dataArray = dataObj.getJSONArray(StringUtils.lowerCase(ConsentExtensionConstants.DATA)); + + ArrayList listData = new ArrayList<>(); + for (int dataIndex = 0; dataIndex < dataArray.length(); dataIndex++) { + listData.add(dataArray.getString(dataIndex)); + } + dataRequested.put(title, listData); + } + returnMaps.put(ConsentExtensionConstants.DATA_REQUESTED, dataRequested); + + //Assigning value of the "Debtor Account" key in the map to the variable "selectedAccount". + if (dataRequested.containsKey("Debtor Account")) { + selectedAccount = getDebtorAccFromConsentData(consentDataArray); + } else { + // add accounts list + request.setAttribute(ConsentExtensionConstants.ACCOUNT_DATA, addAccList(dataSet)); + } + + request.setAttribute(ConsentExtensionConstants.SELECTED_ACCOUNT, selectedAccount); + request.setAttribute(ConsentExtensionConstants.CONSENT_TYPE, ConsentExtensionConstants.VRP); + + return returnMaps; + + } } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/ciba/authenticator/CIBAPushAuthenticator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/ciba/authenticator/CIBAPushAuthenticator.java index a9b04cd9..39f665d8 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/ciba/authenticator/CIBAPushAuthenticator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/ciba/authenticator/CIBAPushAuthenticator.java @@ -127,7 +127,7 @@ public static synchronized void initializeConsentSteps() { * * @param consentData Consent Data * @param jsonObject Json object to store consent data - * @throws ConsentException + * @throws ConsentException when an error occurs while executing retrieval steps */ protected void executeRetrieval(ConsentData consentData, JSONObject jsonObject) throws ConsentException { @@ -146,7 +146,7 @@ protected void executeRetrieval(ConsentData consentData, JSONObject jsonObject) * @param response HTTP response * @param sessionDataKey Session data key * @return Consent data - * @throws ConsentException + * @throws ConsentException when an error occurs while retrieving consent */ protected JSONObject retrieveConsent(HttpServletRequest request, HttpServletResponse response, String sessionDataKey) throws ConsentException { @@ -256,9 +256,9 @@ protected AuthenticationContext getAutenticationContext(String sessionDataKey) { /** * OB specific implementation to retrieve consent data. - * @param sessionDataKey + * @param sessionDataKey Session data key * @return consent data - * @throws AuthenticationFailedException + * @throws AuthenticationFailedException Authentication failed exception */ @Override protected Optional getAdditionalInfo(HttpServletRequest request, HttpServletResponse response, @@ -324,6 +324,7 @@ protected void handlePreConsent(AuthenticationContext context, Map splitQuery(String queryParamsString) throws UnsupportedEncodingException { final Map queryParams = new HashMap<>(); @@ -345,6 +346,7 @@ protected Map splitQuery(String queryParamsString) throws Unsupp * @param httpStatusCode Http status code * @param errorCode Error code * @param errorDescription Error description + * @return CIBAAuthenticationEndpointErrorResponse CIBA Authentication Endpoint Error Response */ public static CIBAAuthenticationEndpointErrorResponse createErrorResponse(int httpStatusCode, String errorCode, String errorDescription) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/AuthErrorCode.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/AuthErrorCode.java index 690db6f4..67234110 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/AuthErrorCode.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/AuthErrorCode.java @@ -24,82 +24,75 @@ public enum AuthErrorCode { /** - * invalid_request, see {@link - * OAuth 2.0}. + * invalid_request, see ... */ INVALID_REQUEST("invalid_request"), /** - * unauthorized_client, see {@link - * OAuth 2.0}. + * unauthorized_client, see ... */ UNAUTHORIZED_CLIENT("unauthorized_client"), /** - * access_denied, see {@link - * OAuth 2.0}. + * access_denied, see ... */ ACCESS_DENIED("access_denied"), /** - * unsupported_response_type, see {@link - * OAuth 2.0}. + * unsupported_response_type, see ... */ UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type"), /** - * invalid_scope, see {@link - * OAuth 2.0}. + * invalid_scope, see ... */ INVALID_SCOPE("invalid_scope"), /** - * server_error, see {@link - * OAuth 2.0}. + * server_error, see ... */ SERVER_ERROR("server_error"), /** - * temporarily_unavailable, see {@link - * OAuth 2.0}. + * temporarily_unavailable, see ... */ TEMPORARILY_UNAVAILABLE("temporarily_unavailable"), /** - * interaction_required, see {@link + * interaction_required, see * OpenID Connect Core 1.0}. */ INTERACTION_REQUIRED("interaction_required"), /** - * login_required, see {@link + * login_required, see * OpenID Connect Core 1.0}. */ LOGIN_REQUIRED("login_required"), /** - * account_selection_required, see {@link + * account_selection_required, see * OpenID Connect Core 1.0}. */ ACCOUNT_SELECTION_REQUIRED("account_selection_required"), /** - * consent_required, see {@link + * consent_required, see * OpenID Connect Core 1.0}. */ CONSENT_REQUIRED("consent_required"), /** - * invalid_request_uri, see {@link + * invalid_request_uri, see * OpenID Connect Core 1.0}. */ INVALID_REQUEST_URI("invalid_request_uri"), /** - * invalid_request_object, see {@link + * invalid_request_object, see * OpenID Connect Core 1.0}. */ INVALID_REQUEST_OBJECT("invalid_request_object"), /** - * request_not_supported, see {@link + * request_not_supported, see * OpenID Connect Core 1.0}. */ REQUEST_NOT_SUPPORTED("request_not_supported"), /** - * request_uri_not_supported, see {@link + * request_uri_not_supported, see * OpenID Connect Core 1.0}. */ REQUEST_URI_NOT_SUPPORTED("request_uri_not_supported"), /** - * registration_not_supported, see {@link + * registration_not_supported, see * OpenID Connect Core 1.0}. */ REGISTRATION_NOT_SUPPORTED("registration_not_supported"); diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentCache.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentCache.java index 42060f2d..7c9cbf35 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentCache.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentCache.java @@ -77,6 +77,7 @@ public static IdentityCache getInstance() { * Add consent data to consent data cache. * @param sessionDataKey session data key * @param consentData consent data + * @throws ConsentManagementException if an error occurs while adding consent data to cache */ public static void addConsentDataToCache(String sessionDataKey, ConsentData consentData) throws ConsentManagementException { @@ -91,6 +92,7 @@ public static void addConsentDataToCache(String sessionDataKey, ConsentData cons * Add consent data to database. * @param sessionDataKey session data key * @param consentData consent data + * @throws ConsentManagementException if an error occurs while storing consent data */ public static void storeConsent(ConsentData consentData, String sessionDataKey) throws ConsentManagementException { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionConstants.java index 6d02d829..4062a1bf 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionConstants.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionConstants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * 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 @@ -16,7 +16,6 @@ * under the License. */ package com.wso2.openbanking.accelerator.consent.extensions.common; -; /** * Constant class for consent extension module. @@ -48,6 +47,8 @@ public class ConsentExtensionConstants { public static final String HTTP_CODE = "httpCode"; public static final String ERRORS = "errors"; public static final String PAYMENTS = "payments"; + public static final String VRP = "vrp"; + public static final String DATA = "Data"; public static final String INITIATION = "Initiation"; public static final String STATUS = "Status"; @@ -92,10 +93,8 @@ public class ConsentExtensionConstants { public static final String ACCOUNTS = "accounts"; public static final String CONSENT_DATA = "consentData"; public static final String TITLE = "title"; - public static final String DATA_SIMPLE = "data"; public static final String DEBTOR_ACCOUNT_ID = "AccountId"; public static final String ACCOUNT_ID = "account_id"; - public static final String DATA_REQUESTED = "data_requested"; public static final String PAYMENT_ACCOUNT = "paymentAccount"; public static final String COF_ACCOUNT = "cofAccount"; @@ -108,7 +107,6 @@ public class ConsentExtensionConstants { public static final String OPENBANKING_INTENT_ID = "openbanking_intent_id"; public static final String VALUE = "value"; public static final String AUTHORIZED_STATUS = "authorised"; - public static final String EXPIRATION_DATE = "ExpirationDateTime"; public static final String EXPIRATION_DATE_TITLE = "Expiration Date Time"; public static final String INSTRUCTED_AMOUNT_TITLE = "Instructed Amount"; @@ -153,19 +151,77 @@ public class ConsentExtensionConstants { public static final String ACCOUNTS_SELF_LINK = "Consent.AccountAPIURL"; public static final String PAYMENT_SELF_LINK = "Consent.PaymentAPIURL"; public static final String COF_SELF_LINK = "Consent.FundsConfirmationAPIURL"; + public static final String VRP_SELF_LINK = "Consent.VRPAPIURL"; public static final String REVOKED_STATUS = "revoked"; - public static final String DISPLAY_NAME = "display_name"; public static final String ACCOUNT_DATA = "account_data"; public static final String SELECTED_ACCOUNT = "selectedAccount"; public static final String PAYMENT_COF_PATH = "funds-confirmation"; - public static final String AWAITING_UPLOAD_STATUS = "awaitingUpload"; - public static final String OB_REVOKED_STATUS = "Revoked"; public static final String OB_REJECTED_STATUS = "Rejected"; public static final String OB_AUTHORIZED_STATUS = "Authorised"; public static final String OB_AWAITING_AUTH_STATUS = "AwaitingAuthorisation"; public static final String OB_AWAITING_UPLOAD_STATUS = "AwaitingUpload"; + //VRP Constants + public static final String VRP_CONSENT_PATH = "domestic-vrp-consents"; + public static final String VRP_PAYMENT = "vrp-payment"; + public static final String PAID_AMOUNT = "paid-amount"; + public static final String LAST_PAYMENT_DATE = "last-payment-date"; + public static final String AUTH_TYPE_AUTHORIZATION = "authorization"; + public static final String CONTROL_PARAMETERS = "ControlParameters"; + public static final String MAXIMUM_INDIVIDUAL_AMOUNT = "MaximumIndividualAmount"; + public static final String MAXIMUM_INDIVIDUAL_AMOUNT_CURRENCY = "MaximumIndividualAmount.Amount.Currency"; + public static final String PERIODIC_LIMITS = "PeriodicLimits"; + public static final String PERIODIC_TYPES = "PeriodicTypes"; + public static final String PERIOD_AMOUNT_LIMIT = "Amount"; + public static final String PERIOD_LIMIT_CURRENCY = "PeriodicLimits.Currency"; + public static final String CYCLIC_EXPIRY_TIME = "cyclicExpiryTime"; + public static final String CYCLIC_REMAINING_AMOUNT = "cyclicRemainingAmount"; + + //vrp period alignment + public static final String PERIOD_ALIGNMENT = "PeriodAlignment"; + + // vrp periodic alignment types + public static final String CONSENT = "Consent"; + public static final String CALENDAR = "Calendar"; + + //vrp periodicLimits + public static final String PERIOD_TYPE = "PeriodType"; + + //vrp periodic types + public static final String DAY = "Day"; + public static final String WEEK = "Week"; + public static final String FORTNIGHT = "Fortnight"; + public static final String MONTH = "Month"; + public static final String HALF_YEAR = "Half-year"; + public static final String YEAR = "Year"; + public static final String VALID_TO_DATE_TIME = "ValidToDateTime"; + public static final String VALID_FROM_DATE_TIME = "ValidFromDateTime"; + public static final String VRP_RESPONSE_PROCESS_PATH = "vrp-response-process"; + + // vrp authorization flow constants + public static final String DOMESTIC_VRP = "Domestic VRP"; + public static final String CONTROL_PARAMETER_MAX_INDIVIDUAL_AMOUNT_TITLE = "Maximum amount per payment"; + public static final String CONTROL_PARAMETER_VALID_TO_DATE_TITLE = "Valid to date and time"; + public static final String CONTROL_PARAMETER_PERIOD_ALIGNMENT_TITLE = "Period Alignment"; + public static final String CONTROL_PARAMETER_PERIOD_TYPE_TITLE = "Period Type"; + public static final Object CONTROL_PARAMETER_AMOUNT_TITLE = "Maximum payment amount per "; + public static final String VRP_ACCOUNT = "vrpAccount"; + public static final Object CONTROL_PARAMETER_VALID_FROM_DATE_TITLE = "Valid from date and time"; + + // VRP submission flow + public static final String ACCOUNT_IDS = "accountIds"; + public static final String INSTRUCTION = "Instruction"; + public static final String REMITTANCE_INFO = "RemittanceInformation"; + public static final String REFERENCE = "Reference"; + public static final String UNSTRUCTURED = "Unstructured"; + public static final String CONTEXT_CODE = "PaymentContextCode"; + public static final String PAYMENT_TYPE = "PaymentType"; + public static final String VRP_PATH = "/domestic-vrps"; + public static final String PREVIOUS_PAID_AMOUNT = "prevPaidAmount"; + public static final String PREVIOUS_LAST_PAYMENT_DATE = "prevLastPaymentDate"; + + } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionUtils.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionUtils.java index 950cb7a0..141410ab 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionUtils.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ConsentExtensionUtils.java @@ -226,9 +226,9 @@ public static Map getSensitiveData(String key) { /** * @param consentDetails json object of consent data - * @param sessionDataKey - * @return - * @throws URISyntaxException + * @param sessionDataKey session data key + * @return ConsentData object + * @throws URISyntaxException if the URI is invalid */ public static ConsentData getConsentDataFromAttributes(JsonObject consentDetails, String sessionDataKey) throws URISyntaxException { @@ -312,6 +312,8 @@ public static boolean isRequestAcceptedPastElapsedTime() { /** * Returns the DateTime by adding given number of days and the with the given Time. * + * @param daysToAdd Number of days to add + * @param time Time to add * @return DateTime value for the day */ public static String constructDateTime(long daysToAdd, String time) { @@ -330,6 +332,7 @@ public static String constructDateTime(long daysToAdd, String time) { * Validates whether Cutoffdatetime is enabled, if the request is arriving past the cut off date and if it * should be rejected by policy. * + * @param timeStamp Initiation timestamp * @return if the request should be rejected, or not. */ public static boolean shouldSubmissionRequestBeRejected(String timeStamp) { @@ -377,8 +380,8 @@ public static String getCurrentCutOffDateTime() { } /** * Convert long date values to ISO 8601 format. - * @param dateValue - * @return + * @param dateValue Date value in long + * @return ISO 8601 formatted date */ public static String convertToISO8601(long dateValue) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ResponseStatus.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ResponseStatus.java index 92fa7009..396599a4 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ResponseStatus.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/ResponseStatus.java @@ -20,167 +20,145 @@ /** * Enum of the supported response status in accelerator. + * HTTP/1.1 documentation - ... */ public enum ResponseStatus { /** - * 200 OK, see {@link - * HTTP/1.1 documentation}. + * 200 OK, see ... */ OK(200, "OK"), /** - * 201 Created, see {@link - * HTTP/1.1 documentation}. + * 201 Created, see ... */ CREATED(201, "Created"), /** - * 202 Accepted, see {@link - * HTTP/1.1 documentation}. + * 202 Accepted, see ... */ ACCEPTED(202, "Accepted"), /** - * 204 No Content, see {@link - * HTTP/1.1 documentation}. + * 204 No Content, see ... */ NO_CONTENT(204, "No Content"), /** - * 205 Reset Content, see {@link - * HTTP/1.1 documentation}. + * 205 Reset Content, see ... * * @since 2.0 */ RESET_CONTENT(205, "Reset Content"), /** - * 206 Reset Content, see {@link - * HTTP/1.1 documentation}. + * 206 Reset Content, see ... * * @since 2.0 */ PARTIAL_CONTENT(206, "Partial Content"), /** - * 301 Moved Permanently, see {@link - * HTTP/1.1 documentation}. + * 301 Moved Permanently, see ... */ MOVED_PERMANENTLY(301, "Moved Permanently"), /** - * 302 Found, see {@link - * HTTP/1.1 documentation}. + * 302 Found, see ... * * @since 2.0 */ FOUND(302, "Found"), /** - * 303 See Other, see {@link - * HTTP/1.1 documentation}. + * 303 See Other, see ... */ SEE_OTHER(303, "See Other"), /** - * 304 Not Modified, see {@link - * HTTP/1.1 documentation}. + * 304 Not Modified, see ... */ NOT_MODIFIED(304, "Not Modified"), /** - * 305 Use Proxy, see {@link - * HTTP/1.1 documentation}. + * 305 Use Proxy, see link - "..." of + * HTTP/1.1 documentation. * * @since 2.0 */ USE_PROXY(305, "Use Proxy"), /** - * 307 Temporary Redirect, see {@link - * HTTP/1.1 documentation}. + * 307 Temporary Redirect, see ... */ TEMPORARY_REDIRECT(307, "Temporary Redirect"), /** - * 400 Bad Request, see {@link - * HTTP/1.1 documentation}. + * 400 Bad Request, see ... */ BAD_REQUEST(400, "Bad Request"), /** - * 401 Unauthorized, see {@link - * HTTP/1.1 documentation}. + * 401 Unauthorized, see ... */ UNAUTHORIZED(401, "Unauthorized"), /** - * 402 Payment Required, see {@link - * HTTP/1.1 documentation}. + * 402 Payment Required, see ... * * @since 2.0 */ PAYMENT_REQUIRED(402, "Payment Required"), /** - * 403 Forbidden, see {@link - * HTTP/1.1 documentation}. + * 403 Forbidden, see ... */ FORBIDDEN(403, "Forbidden"), /** - * 404 Not Found, see {@link - * HTTP/1.1 documentation}. + * 404 Not Found, see ... */ NOT_FOUND(404, "Not Found"), /** - * 405 Method Not Allowed, see {@link - * HTTP/1.1 documentation}. + * 405 Method Not Allowed, see ... * * @since 2.0 */ METHOD_NOT_ALLOWED(405, "Method Not Allowed"), /** - * 406 Not Acceptable, see {@link - * HTTP/1.1 documentation}. + * 406 Not Acceptable, see ... */ NOT_ACCEPTABLE(406, "Not Acceptable"), /** - * 409 Conflict, see {@link - * HTTP/1.1 documentation}. + * 409 Conflict, see ... */ CONFLICT(409, "Conflict"), /** - * 410 Gone, see {@link - * HTTP/1.1 documentation}. + * 410 Gone, see ... */ GONE(410, "Gone"), /** - * 411 Length Required, see {@link - * HTTP/1.1 documentation}. + * 411 Length Required, see ... * * @since 2.0 */ LENGTH_REQUIRED(411, "Length Required"), /** - * 412 Precondition Failed, see {@link - * HTTP/1.1 documentation}. + * 412 Precondition Failed, see ... */ PRECONDITION_FAILED(412, "Precondition Failed"), /** - * 413 Request Entity Too Large, see {@link HTTP/1.1 documentation}. + * 413 Request Entity Too Large, + * see ... * * @since 2.0 */ REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"), /** - * 414 Request-URI Too Long, see {@link - * HTTP/1.1 documentation}. + * 414 Request-URI Too Long, see ... * * @since 2.0 */ REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"), /** - * 415 Unsupported Media Type, see {@link HTTP/1.1 documentation}. + * 415 Unsupported Media Type, + * see ... */ UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), /** - * 416 Requested Range Not Satisfiable, see {@link HTTP/1.1 documentation}. + * 416 Requested Range Not Satisfiable, + * see ... * * @since 2.0 */ REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested Range Not Satisfiable"), /** - * 417 Expectation Failed, see {@link - * HTTP/1.1 documentation}. + * 417 Expectation Failed, + * see ... * * @since 2.0 */ @@ -194,39 +172,34 @@ public enum ResponseStatus { */ TOO_MANY_REQUESTS(429, "Too Many Requests"), /** - * 500 Internal Server Error, see {@link - * HTTP/1.1 documentation}. + * 500 Internal Server Error, see ... */ INTERNAL_SERVER_ERROR(500, "Internal Server Error"), /** - * 501 Not Implemented, see {@link - * HTTP/1.1 documentation}. + * 501 Not Implemented, see ... * * @since 2.0 */ NOT_IMPLEMENTED(501, "Not Implemented"), /** - * 502 Bad Gateway, see {@link - * HTTP/1.1 documentation}. + * 502 Bad Gateway, see ..." * * @since 2.0 */ BAD_GATEWAY(502, "Bad Gateway"), /** - * 503 Service Unavailable, see {@link - * HTTP/1.1 documentation}. + * 503 Service Unavailable, see ... */ SERVICE_UNAVAILABLE(503, "Service Unavailable"), /** - * 504 Gateway Timeout, see {@link - * HTTP/1.1 documentation}. + * 504 Gateway Timeout, see ... * * @since 2.0 */ GATEWAY_TIMEOUT(504, "Gateway Timeout"), /** - * 505 HTTP Version Not Supported, see {@link - * HTTP/1.1 documentation}. + * 505 HTTP Version Not Supported, + * see ... * * @since 2.0 */ diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/factory/AcceleratorConsentExtensionFactory.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/factory/AcceleratorConsentExtensionFactory.java index ef849604..0c15cb9d 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/factory/AcceleratorConsentExtensionFactory.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/factory/AcceleratorConsentExtensionFactory.java @@ -17,19 +17,12 @@ */ package com.wso2.openbanking.accelerator.consent.extensions.common.factory; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist.AccountConsentPersistenceHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist.CofConsentPersistenceHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist.ConsentPersistenceHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.persist.PaymentConsentPersistenceHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval.AccountConsentRetrievalHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval.CofConsentRetrievalHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval.ConsentRetrievalHandler; -import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.handler.retrieval.PaymentConsentRetrievalHandler; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.AccountConsentManageRequestHandler; import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.CofConsentRequestHandler; import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.ConsentManageRequestHandler; import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.PaymentConsentRequestHandler; +import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.VRPConsentRequestHandler; /** * Factory class to get the class based in request type. @@ -55,53 +48,12 @@ public static ConsentManageRequestHandler getConsentManageRequestValidator(Strin case ConsentExtensionConstants.PAYMENT_CONSENT_PATH: consentManageRequestHandler = new PaymentConsentRequestHandler(); break; + case ConsentExtensionConstants.VRP_CONSENT_PATH: + consentManageRequestHandler = new VRPConsentRequestHandler(); + break; default: return null; } return consentManageRequestHandler; - - } - - /** - * Method to get the Consent Authorize Handler. - * - * @param type Type of the request - * @return ConsentAuthorizeHandler - */ - public static ConsentRetrievalHandler getConsentRetrievalHandler(String type) { - - ConsentRetrievalHandler consentRetrieveHandler = null; - - if (type.equalsIgnoreCase(ConsentExtensionConstants.ACCOUNTS)) { - consentRetrieveHandler = new AccountConsentRetrievalHandler(); - } else if (type.equalsIgnoreCase(ConsentExtensionConstants.PAYMENTS)) { - consentRetrieveHandler = new PaymentConsentRetrievalHandler(); - } else if (type.equalsIgnoreCase(ConsentExtensionConstants.FUNDSCONFIRMATIONS)) { - consentRetrieveHandler = new CofConsentRetrievalHandler(); - } - return consentRetrieveHandler; - } - - /** - * Method to get the Consent Persistence Handler. - * - * @param type Type of the request - * @return ConsentPersistenceHandler - */ - public static ConsentPersistenceHandler getConsentPersistenceHandler(String type) { - - ConsentPersistenceHandler consentPersistenceHandler = null; - - if (ConsentExtensionConstants.ACCOUNTS.equalsIgnoreCase(type)) { - consentPersistenceHandler = new AccountConsentPersistenceHandler(); - } else if (ConsentExtensionConstants.PAYMENTS.equalsIgnoreCase(type)) { - consentPersistenceHandler = new PaymentConsentPersistenceHandler(); - } else if (ConsentExtensionConstants.FUNDSCONFIRMATIONS.equalsIgnoreCase(type)) { - consentPersistenceHandler = new CofConsentPersistenceHandler(); - } - return consentPersistenceHandler; - - } - } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyConstants.java new file mode 100644 index 00000000..e9866c25 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyConstants.java @@ -0,0 +1,42 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +/** + * Constants related to idempotency operations. + */ +public class IdempotencyConstants { + + public static final String CONTENT_TYPE_TAG = "content-type"; + public static final String X_IDEMPOTENCY_KEY = "x-idempotency-key"; + public static final String IDEMPOTENCY_KEY_NAME = "IdempotencyKey"; + public static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX"; + public static final String EMPTY_OBJECT = "{}"; + public static final String ERROR_PAYLOAD_NOT_SIMILAR = "Payloads are not similar. Hence this is not a valid" + + " idempotent request"; + public static final String ERROR_AFTER_ALLOWED_TIME = "Request received after the allowed time., Hence this is" + + " not a valid idempotent request"; + public static final String ERROR_MISMATCHING_CLIENT_ID = "Client ID sent in the request does not match with the" + + " client ID in the retrieved consent. Hence this is not a valid idempotent request"; + public static final String ERROR_NO_CONSENT_DETAILS = "No consent details found for the consent ID %s, Hence this" + + " is not a valid idempotent request"; + public static final String JSON_COMPARING_ERROR = "Error occurred while comparing JSON payloads"; + public static final String CONSENT_RETRIEVAL_ERROR = "Error while retrieving detailed consent data"; + public static final String SAME_CONSENT_ID_ERROR = "Cannot use different unique identifier for the same" + + " consent ID when the request does not contain a payload."; +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationException.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationException.java new file mode 100644 index 00000000..821287ca --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationException.java @@ -0,0 +1,35 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +import com.wso2.openbanking.accelerator.common.exception.OpenBankingException; + +/** + * Used for handling exceptions in Idempotency Validation. + */ +public class IdempotencyValidationException extends OpenBankingException { + + public IdempotencyValidationException(String message) { + super(message); + } + + public IdempotencyValidationException(String message, Throwable e) { + super(message, e); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationResult.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationResult.java new file mode 100644 index 00000000..a67f6694 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationResult.java @@ -0,0 +1,82 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource; + +/** + * Class to hold idempotency validation result. + */ +public class IdempotencyValidationResult { + + private boolean isIdempotent; + private boolean isValid; + private DetailedConsentResource consent; + private String consentId; + + public IdempotencyValidationResult() { + } + + public IdempotencyValidationResult(boolean isIdempotent, boolean isValid, DetailedConsentResource consent, + String consentId) { + this.isIdempotent = isIdempotent; + this.isValid = isValid; + this.consent = consent; + this.consentId = consentId; + } + + public IdempotencyValidationResult(boolean isIdempotent, boolean isValid) { + this.isIdempotent = isIdempotent; + this.isValid = isValid; + this.consent = null; + this.consentId = null; + } + + public boolean isIdempotent() { + return isIdempotent; + } + + public void setIsIdempotent(boolean isIdempotent) { + this.isIdempotent = isIdempotent; + } + + public boolean isValid() { + return isValid; + } + + public void setValid(boolean isValid) { + this.isValid = isValid; + } + + public DetailedConsentResource getConsent() { + return consent; + } + + public void setConsent(DetailedConsentResource consent) { + this.consent = consent; + } + + public String getConsentId() { + return consentId; + } + + public void setConsentID(String consentId) { + this.consentId = consentId; + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationUtils.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationUtils.java new file mode 100644 index 00000000..19639519 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidationUtils.java @@ -0,0 +1,131 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; +import com.wso2.openbanking.accelerator.consent.mgt.service.ConsentCoreService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Class to hold idempotency validation utils. + */ +public class IdempotencyValidationUtils { + + private static final Log log = LogFactory.getLog(IdempotencyValidationUtils.class); + private static final ConsentCoreService consentCoreService = ConsentExtensionsDataHolder.getInstance() + .getConsentCoreService(); + + /** + * Method to retrieve the consent ids that have the idempotency key name and value as attribute. + * + * @param idempotencyKeyName Idempotency Key Name + * @param idempotencyKeyValue Idempotency Key Value + * @return List of consent ids if available, else an empty list will be returned + */ + static List getConsentIdsFromIdempotencyKey(String idempotencyKeyName, + String idempotencyKeyValue) { + try { + return consentCoreService.getConsentIdByConsentAttributeNameAndValue( + idempotencyKeyName, idempotencyKeyValue); + } catch (ConsentManagementException e) { + log.debug("No consent ids found for the idempotency key value"); + return new ArrayList<>(); + } + } + + /** + * Method to retrieve the consent ids and idempotency key value using the idempotency key. + * + * @param idempotencyKeyName Idempotency Key Name + * @return Map of consent ids and idempotency key vallue if available, else an empty map will be returned + */ + static Map getAttributesFromIdempotencyKey(String idempotencyKeyName) { + try { + return consentCoreService.getConsentAttributesByName(idempotencyKeyName); + } catch (ConsentManagementException e) { + log.debug("No consent ids found for the idempotency key value"); + return new HashMap<>(); + } + } + + /** + * Method to compare the client ID sent in the request and client id retrieved from the database. + * + * @param requestClientID Client ID sent in the request + * @param dbClientID client ID retrieved from the database + * @return true if the client ID sent in the request and client id retrieved from the database are equal + */ + static boolean isClientIDEqual(String requestClientID, String dbClientID) { + if (requestClientID == null) { + return false; + } + return requestClientID.equals(dbClientID); + } + + /** + * Method to check whether difference between two dates is less than the configured time. + * + * @param createdTime Created Time of the request + * @return true if the request is received within allowed time + */ + static boolean isRequestReceivedWithinAllowedTime(long createdTime) { + + if (createdTime == 0L) { + log.debug("Created time is of the previous request is not correctly set. Hence returning false"); + return false; + } + String allowedTimeDuration = OpenBankingConfigParser.getInstance().getIdempotencyAllowedTime(); + if (StringUtils.isNotBlank(allowedTimeDuration)) { + OffsetDateTime createdDate = OffsetDateTime.parse(toISO8601DateTime(createdTime)); + OffsetDateTime currDate = OffsetDateTime.now(createdDate.getOffset()); + + long diffInMinutes = Duration.between(createdDate, currDate).toMinutes(); + return diffInMinutes <= Long.parseLong(allowedTimeDuration); + } else { + log.error("Idempotency allowed duration is not configured in the system. Hence returning false"); + return false; + } + } + + /** + * Convert long date values to ISO 8601 format. ISO 8601 format - "yyyy-MM-dd'T'HH:mm:ssXXX" + * @param epochDate Date value in epoch format + * @return ISO 8601 formatted date + */ + private static String toISO8601DateTime(long epochDate) { + + DateFormat simple = new SimpleDateFormat(IdempotencyConstants.ISO_FORMAT); + Date simpleDateVal = new Date(epochDate * 1000); + return simple.format(simpleDateVal); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidator.java new file mode 100644 index 00000000..0e6ed237 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidator.java @@ -0,0 +1,301 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.ConsentCoreService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * Class to handle idempotency related operations. + */ +public class IdempotencyValidator { + + private static final Log log = LogFactory.getLog(IdempotencyValidator.class); + private static final ConsentCoreService consentCoreService = ConsentExtensionsDataHolder.getInstance() + .getConsentCoreService(); + + /** + * Method to check whether the request is idempotent. + * This method will first check whether idempotency validation is enabled. After that it will validate whether + * required parameters for validation is present. + * For validation, need to check whether the idempotency key values is present as a consent attribute, if present + * the consent will be retrieved. Finally following conditions will be validated. + * - Whether the client id sent in the request and client id retrieved from the database are equal + * - Whether the difference between two dates is less than the configured time + * - Whether payloads are equal + * + * @param consentManageData Consent Manage Data + * @return IdempotencyValidationResult + * @throws IdempotencyValidationException If an error occurs while validating idempotency + */ + public IdempotencyValidationResult validateIdempotency(ConsentManageData consentManageData) + throws IdempotencyValidationException { + + if (!OpenBankingConfigParser.getInstance().isIdempotencyValidationEnabled()) { + return new IdempotencyValidationResult(false, false); + } + // If request is empty then cannot proceed with idempotency validation + if (consentManageData.getPayload() == null) { + log.error("Request payload is empty. Hence cannot proceed with idempotency validation"); + return new IdempotencyValidationResult(false, false); + } + // If client id is empty then cannot proceed with idempotency validation + if (StringUtils.isBlank(consentManageData.getClientId())) { + log.error("Client ID is empty. Hence cannot proceed with idempotency validation"); + return new IdempotencyValidationResult(false, false); + } + String idempotencyKeyValue = consentManageData.getHeaders().get(getIdempotencyHeaderName()); + // If idempotency key value is empty then cannot proceed with idempotency validation + if (StringUtils.isBlank(idempotencyKeyValue)) { + log.error("Idempotency Key Valueis empty. Hence cannot proceed with idempotency validation"); + return new IdempotencyValidationResult(false, false); + } + try { + String idempotencyKeyName = getIdempotencyAttributeName(consentManageData.getRequestPath()); + if (!IdempotencyConstants.EMPTY_OBJECT.equals(consentManageData.getPayload().toString())) { + // Retrieve consent ids that have the idempotency key name and value as attribute + List consentIds = IdempotencyValidationUtils + .getConsentIdsFromIdempotencyKey(idempotencyKeyName, idempotencyKeyValue); + // Check whether the consent id list is not empty. If idempotency key exists in the database then + // the consent Id list will be not empty. + if (!consentIds.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug(String.format("Idempotency Key %s exists in the database. Hence this is an" + + " idempotent request", idempotencyKeyValue)); + } + for (String consentId : consentIds) { + DetailedConsentResource consentResource = consentCoreService.getDetailedConsent(consentId); + if (consentResource != null) { + return validateIdempotencyConditions(consentManageData, consentResource); + } else { + String errorMsg = String.format(IdempotencyConstants.ERROR_NO_CONSENT_DETAILS, consentId); + log.error(errorMsg); + throw new IdempotencyValidationException(errorMsg); + } + } + } + } else { + return validateIdempotencyWithoutPayload(consentManageData, idempotencyKeyName, idempotencyKeyValue); + } + } catch (IOException e) { + log.error(IdempotencyConstants.JSON_COMPARING_ERROR, e); + throw new IdempotencyValidationException(IdempotencyConstants.JSON_COMPARING_ERROR); + } catch (ConsentManagementException e) { + log.error(IdempotencyConstants.CONSENT_RETRIEVAL_ERROR, e); + return new IdempotencyValidationResult(true, false); + } + return new IdempotencyValidationResult(false, false); + } + + /** + * Method to check whether the idempotency conditions are met for requests without payload. + * This method will validate the following conditions. + * - Whether the idempotency key value is different for the same consent id + * - Whether the client id sent in the request and client id retrieved from the database are equal + * - Whether the difference between two dates is less than the configured time + * - Whether payloads are equal + * + * @param consentManageData Consent Manage Data + * @param idempotencyKeyName Idempotency Key Name + * @param idempotencyKeyValue Idempotency Key value + * @return IdempotencyValidationResult + */ + private IdempotencyValidationResult validateIdempotencyWithoutPayload(ConsentManageData consentManageData, + String idempotencyKeyName, + String idempotencyKeyValue) + throws IdempotencyValidationException, IOException, ConsentManagementException { + + // Retrieve consent ids and idempotency key values that have the idempotency key name + Map attributes = IdempotencyValidationUtils.getAttributesFromIdempotencyKey(idempotencyKeyName); + // Check whether the attributes map is not empty. If idempotency key exists in the database then + // the consent Id list will be not empty. + if (!attributes.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug(String.format("Idempotency Key %s exists in the database. Hence this is an" + + " idempotent request", idempotencyKeyValue)); + } + for (Map.Entry entry : attributes.entrySet()) { + // If the idempotency key value is different for the same consent id then it is not a valid idempotent + if (consentManageData.getRequestPath().contains(entry.getKey()) && + !idempotencyKeyValue.equals(entry.getValue())) { + throw new IdempotencyValidationException(IdempotencyConstants.SAME_CONSENT_ID_ERROR); + } + DetailedConsentResource consentRequest = consentCoreService.getDetailedConsent(entry.getKey()); + if (consentRequest != null) { + return validateIdempotencyConditions(consentManageData, consentRequest); + } else { + String errorMsg = String.format(IdempotencyConstants.ERROR_NO_CONSENT_DETAILS, entry.getKey()); + log.error(errorMsg); + throw new IdempotencyValidationException(errorMsg); + } + } + + } + return new IdempotencyValidationResult(false, false); + } + + /** + * Method to check whether the idempotency conditions are met. + * This method will validate the following conditions. + * - Whether the client id sent in the request and client id retrieved from the database are equal + * - Whether the difference between two dates is less than the configured time + * - Whether payloads are equal + * + * @param consentManageData Consent Manage Data + * @param consentResource Detailed Consent Resource + * @return IdempotencyValidationResult + */ + private IdempotencyValidationResult validateIdempotencyConditions(ConsentManageData consentManageData, + DetailedConsentResource consentResource) + throws IdempotencyValidationException, IOException { + // Compare the client ID sent in the request and client id retrieved from the database + // to validate whether the request is received from the same client + if (IdempotencyValidationUtils.isClientIDEqual(consentResource.getClientID(), + consentManageData.getClientId())) { + // Check whether difference between two dates is less than the configured time + if (IdempotencyValidationUtils.isRequestReceivedWithinAllowedTime(getCreatedTimeOfPreviousRequest( + consentManageData.getRequestPath(), consentResource.getConsentID()))) { + // Compare whether JSON payloads are equal + if (isPayloadSimilar(consentManageData, getPayloadOfPreviousRequest( + consentManageData.getRequestPath(), consentResource.getConsentID()))) { + log.debug("Payloads are similar and request received within allowed" + + " time. Hence this is a valid idempotent request"); + return new IdempotencyValidationResult(true, true, + consentResource, consentResource.getConsentID()); + } else { + log.error(IdempotencyConstants.ERROR_PAYLOAD_NOT_SIMILAR); + throw new IdempotencyValidationException(IdempotencyConstants + .ERROR_PAYLOAD_NOT_SIMILAR); + } + } else { + log.error(IdempotencyConstants.ERROR_AFTER_ALLOWED_TIME); + throw new IdempotencyValidationException(IdempotencyConstants + .ERROR_AFTER_ALLOWED_TIME); + } + } else { + log.error(IdempotencyConstants.ERROR_MISMATCHING_CLIENT_ID); + throw new IdempotencyValidationException(IdempotencyConstants.ERROR_MISMATCHING_CLIENT_ID); + } + } + + /** + * Method to get the Idempotency Attribute Name store in consent Attributes. + * + * @param resourcePath Resource Path + * @return idempotency Attribute Name. + */ + public String getIdempotencyAttributeName(String resourcePath) { + return IdempotencyConstants.IDEMPOTENCY_KEY_NAME; + } + + /** + * Method to get the Idempotency Header Name according to the request. + * + * @return idempotency Header Name. + */ + public String getIdempotencyHeaderName() { + return IdempotencyConstants.X_IDEMPOTENCY_KEY; + } + + /** + * Method to get created time from the Detailed Consent Resource. + * + * @param resourcePath Resource Path + * @param consentId ConsentId + * @return Created Time. + */ + public long getCreatedTimeOfPreviousRequest(String resourcePath, String consentId) { + DetailedConsentResource consentRequest = null; + try { + consentRequest = consentCoreService.getDetailedConsent(consentId); + } catch (ConsentManagementException e) { + log.error(IdempotencyConstants.CONSENT_RETRIEVAL_ERROR, e); + return 0L; + } + if (consentRequest == null) { + return 0L; + } + return consentRequest.getCreatedTime(); + } + + /** + * Method to get payload from previous request. + * + * @param resourcePath Resource Path + * @param consentId ConsentId + * @return Map containing the payload. + */ + public String getPayloadOfPreviousRequest(String resourcePath, String consentId) { + DetailedConsentResource consentRequest = null; + try { + consentRequest = consentCoreService.getDetailedConsent(consentId); + } catch (ConsentManagementException e) { + log.error(IdempotencyConstants.CONSENT_RETRIEVAL_ERROR, e); + return null; + } + if (consentRequest == null) { + return null; + } + return consentRequest.getReceipt(); + } + + /** + * Method to compare whether payloads are equal. + * + * @param consentManageData Consent Manage Data Object + * @param consentReceipt Payload received from database + * @return Whether payloads are equal + */ + public boolean isPayloadSimilar(ConsentManageData consentManageData, String consentReceipt) { + + if (consentManageData.getPayload() == null || consentReceipt == null) { + return false; + } + + JsonNode expectedNode = null; + JsonNode actualNode = null; + try { + ObjectMapper mapper = new ObjectMapper(); + expectedNode = mapper.readTree(consentManageData.getPayload().toString()); + actualNode = mapper.readTree(consentReceipt); + if (log.isDebugEnabled()) { + log.debug(String.format("Expected payload for idempotent request is: %s. But actual payload " + + "received is %s", expectedNode.toString(), actualNode.toString())); + } + } catch (JsonProcessingException e) { + log.error(IdempotencyConstants.JSON_COMPARING_ERROR, e); + return false; + } + return expectedNode.equals(actualNode); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/event/executors/VRPEventExecutor.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/event/executors/VRPEventExecutor.java new file mode 100644 index 00000000..126ad48a --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/event/executors/VRPEventExecutor.java @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.wso2.openbanking.accelerator.consent.extensions.event.executors; + +import com.wso2.openbanking.accelerator.common.event.executor.OBEventExecutor; +import com.wso2.openbanking.accelerator.common.event.executor.model.OBEvent; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.PeriodicLimit; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * This class is responsible for executing Variable Recurring Payments (VRP) events. + * It implements the OBEventExecutor interface and overrides its methods to provide + * specific implementations for VRP events. + */ +public class VRPEventExecutor implements OBEventExecutor { + + public static List validateInstructedAmountWithControlParameters(BigDecimal instructedAmount, + JSONObject controlParameters) { + + /** + * Validates the instructed amount with control parameters and returns a list of PeriodicLimit objects. + * If the instructed amount is greater than the maximum individual amount or the cyclic remaining amount, + * an empty list is returned. If the JSON parsing fails, an empty list is also returned. + * + * @param instructedAmount The instructed amount to be validated + * @param controlParameters The control parameters to be used for validation + * @return A list of PeriodicLimit objects + */ + List periodicLimitsList = new ArrayList<>(); + + BigDecimal maxIndividualAmount = BigDecimal.valueOf(Double.parseDouble(controlParameters. + getAsString(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT))); + + if (instructedAmount.compareTo(maxIndividualAmount) > 0) { + return periodicLimitsList; + } + + JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE); + JSONArray periodicLimits; + + try { + periodicLimits = (JSONArray) parser.parse(controlParameters. + getAsString(ConsentExtensionConstants.PERIODIC_LIMITS)); + } catch (ParseException e) { + // Log the error or handle it as needed + return periodicLimitsList; + } + + long currentMoment = System.currentTimeMillis() / 1000; + + for (Object obj : periodicLimits) { + JSONObject limit = (JSONObject) obj; + BigDecimal amount = BigDecimal. + valueOf(Double.parseDouble(limit.getAsString(ConsentExtensionConstants.AMOUNT))); + long cyclicExpiryTime = Long.parseLong(limit.getAsString(ConsentExtensionConstants.CYCLIC_EXPIRY_TIME)); + BigDecimal cyclicRemainingAmount = BigDecimal. + valueOf(Double.parseDouble(limit.getAsString(ConsentExtensionConstants.CYCLIC_REMAINING_AMOUNT))); + + String periodType = limit.getAsString(ConsentExtensionConstants.PERIOD_TYPE); + String periodAlignment = limit.getAsString(ConsentExtensionConstants.PERIOD_ALIGNMENT); + + PeriodicLimit periodicLimit = new PeriodicLimit(periodType, amount, periodAlignment); + + if (currentMoment <= cyclicExpiryTime) { + if (instructedAmount.compareTo(cyclicRemainingAmount) > 0) { + return periodicLimitsList; + } else { + cyclicRemainingAmount = cyclicRemainingAmount.subtract(instructedAmount); + } + } else { + while (currentMoment > periodicLimit.getCyclicExpiryTime()) { + periodicLimit.setCyclicExpiryTime(); + } + cyclicRemainingAmount = amount; + if (instructedAmount.compareTo(cyclicRemainingAmount) > 0) { + return periodicLimitsList; + } else { + cyclicRemainingAmount = cyclicRemainingAmount.subtract(instructedAmount); + } + } + periodicLimitsList.add(periodicLimit); + } + + return periodicLimitsList; + } + + /** + * Processes the given OBEvent. This method is part of the OBEventExecutor interface and needs to be implemented. + * + * @param obEvent The OBEvent to be processed + */ + @Override + public void processEvent(OBEvent obEvent) { + + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/AccountConsentManageRequestHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/AccountConsentManageRequestHandler.java index 166e2e9d..83d7d0f2 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/AccountConsentManageRequestHandler.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/AccountConsentManageRequestHandler.java @@ -302,7 +302,7 @@ private static boolean isTransactionFromToTimeValid(String fromDateVal, String t /** * Method to append the consent expiration time (UTC) as a consent attribute. - * + * @param requestedConsent Consent Resource */ public static void appendConsentExpirationTimestampAttribute(ConsentResource requestedConsent) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/VRPConsentRequestHandler.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/VRPConsentRequestHandler.java new file mode 100644 index 00000000..9ff83ac1 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/impl/VRPConsentRequestHandler.java @@ -0,0 +1,342 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.impl; + +import com.google.gson.Gson; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.PeriodicLimit; +import com.wso2.openbanking.accelerator.consent.extensions.manage.validator.VRPConsentRequestValidator; +import com.wso2.openbanking.accelerator.consent.extensions.util.ConsentManageUtil; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.wso2.openbanking.accelerator.consent.extensions.common. + ConsentExtensionConstants.AUTH_TYPE_AUTHORIZATION; +import static com.wso2.openbanking.accelerator.consent.extensions. + common.ConsentExtensionConstants.CREATED_STATUS; + +/** + * Consent Manage request handler class for VRP Payment Request Validation. + */ +public class VRPConsentRequestHandler implements ConsentManageRequestHandler { + + private static final Log log = LogFactory.getLog(VRPConsentRequestHandler.class); + + + /** + * This method is responsible for processing a Variable Recurring Payment Consent Manage POST request. + * It validates the payment request, checks for the existence of an idempotency key. + * + * @param consentManageData Object + */ + @Override + public void handleConsentManagePost(ConsentManageData consentManageData) { + + try { + Object request = consentManageData.getPayload(); + + JSONObject validationResponse = VRPConsentRequestValidator.validateVRPPayload(request); + + if (!(Boolean.parseBoolean(validationResponse.getAsString(ConsentExtensionConstants.IS_VALID)))) { + log.error(validationResponse.get(ConsentExtensionConstants.ERRORS)); + throw new ConsentException((ResponseStatus) validationResponse + .get(ConsentExtensionConstants.HTTP_CODE), + String.valueOf(validationResponse.get(ConsentExtensionConstants.ERRORS))); + } + + if (StringUtils.isEmpty(consentManageData.getHeaders() + .get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY))) { + log.error(ErrorConstants.IDEMPOTENCY_KEY_NOT_FOUND); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.IDEMPOTENCY_KEY_NOT_FOUND); + } + + //Handle payment initiation flows + handlePaymentPost(consentManageData, request); + + } catch (ConsentManagementException e) { + log.error("Error occurred while handling the initiation request", e); + throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, + ErrorConstants.VRP_INITIATION_HANDLE_ERROR); + } + } + + /** + * This method is responsible for handling the GET request for retrieving consent initiation details. + * It validates the consent ID, checks if the consent exists,verifies if the consent belongs to the + * client making the request. + * + * @param consentManageData Object + */ + @Override + public void handleConsentManageGet(ConsentManageData consentManageData) { + + String consentId = consentManageData.getRequestPath().split("/")[1]; + if (ConsentManageUtil.isConsentIdValid(consentId)) { + try { + ConsentResource consent = ConsentServiceUtil.getConsentService().getConsent(consentId, + false); + // Check whether the client id is matching + if (!consent.getClientID().equals(consentManageData.getClientId())) { + // Throws the error if the client Ids mismatch + if (log.isDebugEnabled()) { + log.debug(String.format("ClientIds missmatch. " + + "Retrieved client id: %s, ConsentmanageData client id: %s", + consent.getClientID(), consentManageData.getClientId())); + } + + throw new ConsentException(ResponseStatus.BAD_REQUEST, + "Invalid client id passed"); + } + + JSONObject receiptJSON = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE). + parse(consent.getReceipt()); + consentManageData.setResponsePayload(ConsentManageUtil + .getInitiationRetrievalResponse(receiptJSON, consent, consentManageData, + ConsentExtensionConstants.VRP)); + consentManageData.setResponseStatus(ResponseStatus.OK); + } catch (ConsentManagementException | ParseException e) { + log.error(ErrorConstants.INVALID_CLIENT_ID_MATCH, e); + throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, + ErrorConstants.VRP_INITIATION_RETRIEVAL_ERROR); + } + } else { + log.error(ErrorConstants.INVALID_CONSENT_ID); + throw new ConsentException(ResponseStatus.BAD_REQUEST, ErrorConstants.INVALID_CONSENT_ID); + } + } + + /** + * Handles the DELETE request for revoking or deleting a consent. + * + * @param consentManageData Object containing request details + */ + @Override + public void handleConsentManageDelete(ConsentManageData consentManageData) { + + ConsentManageUtil.handleConsentManageDelete(consentManageData); + } + + /** + * Method to handle Variable Recurring Payment POST requests. + * This private method processes Variable Recurring Payment POST requests, creating a new consent + * based on the provided request payload. It performs the following actions: + * - Creates a DetailedConsentResource representing the consent initiation. + * - Stores consent attributes, including the idempotency key. + * - Constructs the response payload containing initiation details and sets appropriate headers. + * - Sets the response status to Created. + * + * @param consentManageData Object containing request details, including client ID, request payload, headers. + * @param request Object + * @throws ConsentManagementException if an error occurs while creating the consent or storing consent attributes. + */ + public void handlePaymentPost(ConsentManageData consentManageData, Object request) + throws ConsentManagementException { + + // Check if the request is a JSONObject + if (!(request instanceof JSONObject)) { + log.error("Invalid request type. Expected JSONObject."); + throw new ConsentException(ResponseStatus.INTERNAL_SERVER_ERROR, + ErrorConstants.PAYLOAD_FORMAT_ERROR); + } + + JSONObject requestObject = (JSONObject) request; + + // Create a ConsentResource representing the requested consent + ConsentResource requestedConsent = createRequestedConsent(consentManageData, requestObject); + + // Create the consent + DetailedConsentResource createdConsent = createConsent(requestedConsent); + + // Set consent attributes for storing + Map consentAttributes = createConsentAttributes(consentManageData); + + // Store consent attributes + ConsentServiceUtil.getConsentService().storeConsentAttributes(createdConsent.getConsentID(), + consentAttributes); + + // Set response payload and headers + setResponse(consentManageData, requestObject, createdConsent); + } + + /** + * Method to Create a ConsentResource object using the provided ConsentManageData and requestObject. + * + * @param consentManageData Object containing request details + * @param requestObject JSON object representing the request + * @return ConsentResource object + */ + private ConsentResource createRequestedConsent(ConsentManageData consentManageData, JSONObject requestObject) { + return new ConsentResource(consentManageData.getClientId(), + requestObject.toJSONString(), ConsentExtensionConstants.VRP, + ConsentExtensionConstants.AWAITING_AUTH_STATUS); + } + + /** + * Method to create a DetailedConsentResource object using the provided ConsentResource. + * + * @param requestedConsent ConsentResource object + * @return DetailedConsentResource object + * @throws ConsentManagementException if an error occurs while creating the consent + */ + private DetailedConsentResource createConsent(ConsentResource requestedConsent) throws ConsentManagementException { + return ConsentServiceUtil.getConsentService() + .createAuthorizableConsent(requestedConsent, null, + CREATED_STATUS, AUTH_TYPE_AUTHORIZATION, true); + } + + /** + * Method to Create a map of consent attributes using the provided ConsentManageData. + * + * @param consentManageData Object containing request details + * @return Map of consent attributes + */ + private Map createConsentAttributes(ConsentManageData consentManageData) { + Map consentAttributes = new HashMap<>(); + consentAttributes.put(ConsentExtensionConstants.IDEMPOTENCY_KEY, consentManageData.getHeaders() + .get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY)); + + JSONObject controlParameters = getControlParameters(consentManageData); + JSONArray periodicLimitsArray = (JSONArray) controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + + List periodicLimitsList = createPeriodicLimitsList(periodicLimitsArray); + + JSONObject controlParams = createControlParameters(controlParameters, periodicLimitsList); + + // Convert the JSONObject to a string + String consentAttributesJson = controlParams.toJSONString(); + + // Add the consentAttributesJson to the consentAttributes + consentAttributes.put(ConsentExtensionConstants.CONTROL_PARAMETERS, consentAttributesJson); + + return consentAttributes; + } + + /** + * Method to retrieve control parameters from the provided ConsentManageData. + * + * @param consentManageData Object containing request details + * @return JSONObject of control parameters + */ + private JSONObject getControlParameters(ConsentManageData consentManageData) { + return (JSONObject) ((JSONObject) ((JSONObject) consentManageData.getPayload()) + .get(ConsentExtensionConstants.DATA)).get(ConsentExtensionConstants.CONTROL_PARAMETERS); + } + + /** + * Method to create a list of PeriodicLimit objects from the provided JSONArray. + * + * @param periodicLimitsArray JSONArray of periodic limits + * @return List of PeriodicLimit objects + */ + private List createPeriodicLimitsList(JSONArray periodicLimitsArray) { + List periodicLimitsList = new ArrayList<>(); + + for (Object periodicLimit : periodicLimitsArray) { + JSONObject jsonObject = (JSONObject) periodicLimit; + String periodType = (String) jsonObject.get(ConsentExtensionConstants.PERIOD_TYPE); + BigDecimal amount = BigDecimal.valueOf(Double.parseDouble((String) jsonObject.get(ConsentExtensionConstants. + AMOUNT))); + String periodAlignment = (String) jsonObject.get(ConsentExtensionConstants.PERIOD_ALIGNMENT); + + PeriodicLimit periodicLimits = new PeriodicLimit(periodType, amount, periodAlignment); + periodicLimitsList.add(periodicLimits); + } + + return periodicLimitsList; + } + + /** + * Method to create JSONObject of control parameters using the provided JSONObject and + * list of PeriodicLimit objects. + * + * @param controlParameters JSONObject of control parameters + * @param periodicLimitsList List of PeriodicLimit objects + * @return JSONObject of control parameters + */ + private JSONObject createControlParameters(JSONObject controlParameters, List periodicLimitsList) { + Gson gson = new Gson(); + + // Get MaximumIndividualAmount from controlParameters + JSONObject maximumIndividualAmountObject = (JSONObject) controlParameters. + get(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT); + double maximumIndividualAmount = Double.parseDouble(maximumIndividualAmountObject + .get(ConsentExtensionConstants.AMOUNT).toString()); + + // Create a new JSONObject + JSONObject jsonObject = new JSONObject(); + + // Add MaximumIndividualAmount to the JSONObject + jsonObject.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, maximumIndividualAmount); + + // Convert the periodicLimitsList to a JSON string + String periodicLimitsJson = gson.toJson(periodicLimitsList); + + // Parse the JSON string back to a JSONArray + JSONArray newPeriodicLimitsArray; + try { + newPeriodicLimitsArray = (JSONArray) new JSONParser(JSONParser.MODE_PERMISSIVE).parse(periodicLimitsJson); + } catch (ParseException e) { + throw new RuntimeException("Error parsing JSON", e); + } + + // Add the PeriodicLimits array to the JSONObject + jsonObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, newPeriodicLimitsArray); + + return jsonObject; + } + + /** + * Method to set the response payload, headers, and status for the provided ConsentManageData using the + * provided requestObject and createdConsent. + * + * @param consentManageData Object containing request details + * @param requestObject JSON object representing the request + * @param createdConsent DetailedConsentResource object representing the created consent + */ + private void setResponse(ConsentManageData consentManageData, + JSONObject requestObject, DetailedConsentResource createdConsent) { + consentManageData.setResponsePayload(ConsentManageUtil.getInitiationResponse(requestObject, createdConsent, + consentManageData, ConsentExtensionConstants.VRP)); + + // Get request headers + Map headers = consentManageData.getHeaders(); + + consentManageData.setResponseHeader(ConsentExtensionConstants.X_IDEMPOTENCY_KEY, + headers.get(ConsentExtensionConstants.X_IDEMPOTENCY_KEY)); + consentManageData.setResponseStatus(ResponseStatus.CREATED); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/model/PeriodicLimit.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/model/PeriodicLimit.java new file mode 100644 index 00000000..6bce52bb --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/model/PeriodicLimit.java @@ -0,0 +1,202 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.model; + +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.util.PeriodicTypesEnum; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.Month; +import java.time.Period; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAdjusters; + +/** + * This class represents a periodic limit for a VRP consent. + * It includes the period type, amount, period alignment, cyclic expiry time, and cyclic paid amount. + */ +public class PeriodicLimit { + + private final String periodType; + private BigDecimal amount; + private String periodAlignment; + private long cyclicExpiryTime; + private BigDecimal cyclicRemainingAmount; + + /** + * Constructs a new PeriodicLimit with the specified period type, amount, and period alignment. + * It also calculates and sets the cyclic expiry time and cyclic paid amount. + * + * @param periodType the period type + * @param amount the amount + * @param periodAlignment the period alignment + */ + public PeriodicLimit(String periodType, BigDecimal amount, String periodAlignment) { + this.periodType = periodType; + this.amount = amount; + this.periodAlignment = periodAlignment; + setCyclicExpiryTime(); + calculateCyclicPaidAmount(); + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getPeriodAlignment() { + return periodAlignment; + } + + public void setPeriodAlignment(String periodAlignment) { + this.periodAlignment = periodAlignment; + } + + public long getCyclicExpiryTime() { + return cyclicExpiryTime; + } + + public BigDecimal getCyclicRemainingAmount() { + return cyclicRemainingAmount; + } + + public void setCyclicRemainingAmount(BigDecimal cyclicRemainingAmount) { + this.cyclicRemainingAmount = cyclicRemainingAmount; + } + + /** + * Calculates and sets the cyclic expiry time based on the period type and period alignment. + */ + public void setCyclicExpiryTime() { + Instant now = Instant.now(); + Instant expiryTime; + + if (periodAlignment.equals(ConsentExtensionConstants.CONSENT)) { + expiryTime = calculateExpiryTimeForConsent(now); + } else if (periodAlignment.equals(ConsentExtensionConstants.CALENDAR)) { + expiryTime = calculateExpiryTimeForCalendar(now); + } else { + throw new IllegalArgumentException("Invalid PeriodAlignment"); + } + + cyclicExpiryTime = expiryTime.getEpochSecond(); + } + + + /** + * Calculates the expiry time for a consent based on the period type. + * + * @param now the current time + * @return the expiry time for a consent + */ + private Instant calculateExpiryTimeForConsent(Instant now) { + PeriodicTypesEnum periodType = PeriodicTypesEnum.valueOf(this.periodType.toUpperCase()); + switch (periodType) { + case DAY: + return now.plus(Duration.ofDays(1)); + case WEEK: + return now.plus(Duration.ofDays(7)); + case FORTNIGHT: + return now.plus(Duration.ofDays(14)); + case MONTH: + return now.plus(Period.ofMonths(1)); + case HALF_YEAR: + return now.plus(Period.ofMonths(6)); + case YEAR: + return now.plus(Period.ofYears(1)); + default: + throw new IllegalArgumentException("Invalid PeriodType"); + } + } + + /** + * Calculates the expiry time for a calendar based on the period type. + * + * @param now the current time + * @return the expiry time for a calendar + */ + private Instant calculateExpiryTimeForCalendar(Instant now) { + LocalDate localDate = now.atZone(ZoneId.systemDefault()).toLocalDate(); + PeriodicTypesEnum periodType = PeriodicTypesEnum.valueOf(this.periodType.toUpperCase()); + switch (periodType) { + case DAY: + return localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant(); + case WEEK: + return localDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).atStartOfDay(ZoneId.systemDefault()) + .toInstant(); + case FORTNIGHT: + return now.plus(Duration.ofDays(14)); + case MONTH: + return localDate.with(TemporalAdjusters.firstDayOfNextMonth()). + atStartOfDay(ZoneId.systemDefault()).toInstant(); + case HALF_YEAR: + return calculateHalfYearExpiry(localDate); + case YEAR: + return localDate.with(TemporalAdjusters.firstDayOfNextYear()).atStartOfDay(ZoneId.systemDefault()) + .toInstant(); + default: + throw new IllegalArgumentException("Invalid PeriodType"); + } + } + + /** + * Calculates the expiry time for a half year. + * + * @param localDate the current date + * @return the expiry time for a half year + */ + private Instant calculateHalfYearExpiry(LocalDate localDate) { + Month currentMonth = localDate.getMonth(); + if (currentMonth.getValue() < 7) { + return localDate.withMonth(6).with(TemporalAdjusters.lastDayOfMonth()).atStartOfDay(ZoneId.systemDefault()) + .toInstant(); + } else { + return localDate.withMonth(12).with(TemporalAdjusters.lastDayOfMonth()) + .atStartOfDay(ZoneId.systemDefault()) + .toInstant(); + } + } + + /** + * Calculates and sets the cyclic paid amount based on the period alignment. + */ + private void calculateCyclicPaidAmount() { + + if (periodAlignment.equalsIgnoreCase(ConsentExtensionConstants.CONSENT)) { + cyclicRemainingAmount = BigDecimal.valueOf(0); + } else if (periodAlignment.equalsIgnoreCase(ConsentExtensionConstants.CALENDAR)) { + LocalDate now = LocalDate.now(); + LocalDate expiryDate = Instant.ofEpochSecond(cyclicExpiryTime).atZone(ZoneId.systemDefault()) + .toLocalDate(); + BigDecimal divisor = BigDecimal.valueOf(PeriodicTypesEnum.valueOf(this.periodType.toUpperCase()) + .getDivisor()); + BigDecimal days = BigDecimal.valueOf(ChronoUnit.DAYS.between(now, expiryDate)); + cyclicRemainingAmount = amount.divide(divisor, RoundingMode.HALF_UP).multiply(days) + .setScale(2, RoundingMode.HALF_UP); + } + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/CofConsentRequestValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/CofConsentRequestValidator.java index 6a72bdac..9007ace6 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/CofConsentRequestValidator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/CofConsentRequestValidator.java @@ -35,8 +35,8 @@ public class CofConsentRequestValidator { /** * Method to validate COF initiation request. - * @param initiation - * @return + * @param initiation Initiation Object + * @return JSONObject Validation Response */ public static JSONObject validateCOFInitiation(JSONObject initiation) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/PaymentsConsentRequestValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/PaymentsConsentRequestValidator.java index 845860a9..2653591e 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/PaymentsConsentRequestValidator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/PaymentsConsentRequestValidator.java @@ -32,7 +32,7 @@ public class PaymentsConsentRequestValidator { * * @param requestPath Request Path of the request * @param initiation Initiation Object - * @return + * @return JSONObject Validation Response */ public static JSONObject validatePaymentInitiation(String requestPath, JSONObject initiation) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/VRPConsentRequestValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/VRPConsentRequestValidator.java new file mode 100644 index 00000000..0c4f1847 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/manage/validator/VRPConsentRequestValidator.java @@ -0,0 +1,815 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.validator; + +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.util.ConsentManageUtil; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Consent Manage validator class for Variable Recurring Payment Request Validation. + */ +public class VRPConsentRequestValidator { + + private static final Log log = LogFactory.getLog(VRPConsentRequestValidator.class); + + /** + * Method to validate a variable recurring payment request. + * This method performs validation on the variable recurring payment request. + * It checks the validity of the data body, the initiation payload, control parameters, + * and ensures that the risk information is present. If any validation fails, the method returns a detailed + * validation response indicating the error. If all validations pass, the returned validation response + * indicates that the initiation request is valid. + * + * @param request The initiation object containing the variable recurring payment initiation request. + * @return A validation response object indicating whether the initiation request is valid. + */ + public static JSONObject validateVRPPayload(Object request) { + + JSONObject validationResponse = new JSONObject(); + validationResponse.put(ConsentExtensionConstants.IS_VALID, false); + + //Get the request payload from the ConsentManageData + if (!(request instanceof JSONObject)) { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR); + } + + JSONObject requestBody = (JSONObject) request; + //Check request body is valid and not empty + JSONObject dataValidationResult = ConsentManageUtil.validateInitiationDataBody(requestBody); + + if (!(Boolean.parseBoolean(dataValidationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return dataValidationResult; + } + + //Check consent initiation is valid and not empty + JSONObject initiationValidationResult = VRPConsentRequestValidator.validateConsentInitiation(requestBody); + + if (!(Boolean.parseBoolean(initiationValidationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return initiationValidationResult; + } + + JSONObject controlParameterValidationResult = VRPConsentRequestValidator. + validateConsentControlParameters(requestBody); + + if (!(Boolean.parseBoolean(controlParameterValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return controlParameterValidationResult; + } + + JSONObject riskValidationResult = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + if (!(Boolean.parseBoolean(riskValidationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return riskValidationResult; + } + + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Method to validate control parameters for variable recurring payments. + * This method performs validation on the control parameters for variable recurring payments. + * It checks the validity of maximum individual amount, requested execution date-time, and periodic limits. + * If any validation fails, the method returns a detailed validation response indicating the error. + * If all validations pass, the returned validation response indicates that the control parameters are valid. + * + * @param controlParameters The initiation object containing control parameters for variable recurring payments. + * @return A validation response object indicating whether the control parameters are valid. + */ + public static JSONObject validateControlParameters(JSONObject controlParameters) { + JSONObject validationResponse = new JSONObject(); + + JSONObject maximumIndividualAmountResult = validateMaximumIndividualAmount(controlParameters); + if (!(Boolean.parseBoolean(maximumIndividualAmountResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return maximumIndividualAmountResult; + } + + JSONObject maximumIndividualAmountCurrencyValidationResult = validateMaximumIndividualAmountCurrency + (controlParameters); + if (!(Boolean.parseBoolean(maximumIndividualAmountCurrencyValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return maximumIndividualAmountCurrencyValidationResult; + } + + JSONObject parameterDateTimeValidationResult = validateParameterDateTime(controlParameters); + if (!(Boolean.parseBoolean(parameterDateTimeValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return parameterDateTimeValidationResult; + } + + // Validate Periodic Limits + JSONObject periodicLimitsValidationResult = validatePeriodicLimits(controlParameters); + if (!(Boolean.parseBoolean(periodicLimitsValidationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return periodicLimitsValidationResult; + } + + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Checks whether the given object is a valid JSONArray. + * This method verifies if the provided object is not null and is an instance of JSONArray. + * It is commonly used to validate whether a given object represents a valid JSON array. + * + * @param value The object to be checked for being a valid JSONArray. + * @return true if the object is a valid JSONArray, false otherwise. + */ + public static boolean isValidJSONArray(Object value) { + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, "periodic limit", + "JSONObject"); + return value instanceof JSONArray; + } + + /** + * Validates the Maximum Individual Amount in the control parameters of a consent request. + * + * @param controlParameters The JSON object representing the control parameters of the consent request. + * @return A JSON object containing the validation response. + */ + public static JSONObject validateMaximumIndividualAmount(JSONObject controlParameters) { + + JSONObject validationResponse = new JSONObject(); + + //Validate Maximum individual amount in control parameters + if (controlParameters.containsKey(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT)) { + + Object maximumIndividualAmount = controlParameters. + get(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT); + + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, + "maximum individual amount", "JSONObject"); + + // Check if the control parameter is valid + if (!isValidJSONObject(maximumIndividualAmount)) { + return ConsentManageUtil.getValidationResponse(errorMessage); + } + + JSONObject maximumIndividualAmountResult = validateJsonObjectKey((JSONObject) maximumIndividualAmount, + ConsentExtensionConstants.AMOUNT, String.class); + if (!(Boolean.parseBoolean(maximumIndividualAmountResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return maximumIndividualAmountResult; + } + } else { + log.error(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT); + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT); + + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the Currency in Maximum Individual Amount in the control parameters of a consent request. + * + * @param controlParameters The JSON object representing the control parameters of the consent request. + * @return A JSON object containing the validation response. + */ + public static JSONObject validateMaximumIndividualAmountCurrency(JSONObject controlParameters) { + // Retrieve the maximum individual amount from the control parameters + Object maximumIndividualAmount = controlParameters.get(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT); + + // Validate the currency of the maximum individual amount + JSONObject maximumIndividualAmountValidationResult = validateJsonObjectKey((JSONObject) maximumIndividualAmount, + ConsentExtensionConstants.CURRENCY, String.class); + if (!(Boolean.parseBoolean(maximumIndividualAmountValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return maximumIndividualAmountValidationResult; + } + String maximumIndividualAmountCurrency; + maximumIndividualAmountCurrency = ((JSONObject) maximumIndividualAmount). + getAsString(ConsentExtensionConstants.CURRENCY); + + // Retrieve the periodic limits from the control parameters + JSONArray periodicLimits = (JSONArray) controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + + // Iterate over the periodic limits and check if the currency of the limit is the same as the currency + // of maximum individual amount + for (Object limitObj : periodicLimits) { + if (limitObj instanceof JSONObject) { + JSONObject limit = (JSONObject) limitObj; + String limitCurrency = limit.getAsString(ConsentExtensionConstants.CURRENCY); + if (!maximumIndividualAmountCurrency.equals(limitCurrency)) { + log.error(ErrorConstants.CURRENCY_MISMATCH); + return ConsentManageUtil.getValidationResponse(ErrorConstants.FIELD_INVALID, + ErrorConstants.CURRENCY_MISMATCH, + ErrorConstants.PATH_PERIOD_LIMIT_CURRENCY); + } + } + } + + // If all validations pass, return a valid response + JSONObject validationResponse = new JSONObject(); + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Method to validate variable recurring payment periodic limits. + * This method validates the periodic limits specified in the control parameters for variable recurring payments. + * It checks if the provided JSON array of periodic limits is valid and then iterates through each limit + * to ensure that required fields such as amount, currency, period alignment, and period type are present and + * meet the specified criteria. + * + * @param controlParameters Initiation Object containing periodic limits + * @return validation response object indicating whether the provided periodic limits are valid + */ + public static JSONObject validatePeriodicLimits(JSONObject controlParameters) { + JSONObject validationResponse = new JSONObject(); + + // Check if the periodic limits key is present + if (controlParameters.containsKey(ConsentExtensionConstants.PERIODIC_LIMITS)) { + + // Retrieve the periodic limits from the control parameters + Object periodicLimit = controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + + // Check if the control parameter is a valid JSON array + if (!isValidJSONArray(periodicLimit)) { + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_PARAMETER_PERIODIC_LIMITS); + } + JSONArray periodicLimits = (JSONArray) controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + // Create a set to store the periodTypes + Set periodTypes = new HashSet<>(); + Iterator parameters = periodicLimits.iterator(); + + while (parameters.hasNext()) { + JSONObject limit = (JSONObject) parameters.next(); + JSONObject amountValidationResult = validateAmountPeriodicLimit(controlParameters); + if (!(Boolean.parseBoolean(amountValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return amountValidationResult; + } + + JSONObject currencyValidationResult = validateCurrencyPeriodicLimit(controlParameters); + if (!(Boolean.parseBoolean(currencyValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return currencyValidationResult; + } + + JSONObject periodAlignmentValidationResult = validatePeriodAlignment(limit); + if (!(Boolean.parseBoolean(periodAlignmentValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return periodAlignmentValidationResult; + } + + JSONObject periodTypeValidationResult = validatePeriodType(limit); + if (!(Boolean.parseBoolean(periodTypeValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return periodTypeValidationResult; + } + + //Check if periodicLimits size exceeds 6 + if (periodicLimits.size() > ErrorConstants.MAXIMUM_PERIODIC_LIMITS) { + log.error(ErrorConstants.INVALID_PERIODIC_LIMIT_SIZE); + return ConsentManageUtil.getValidationResponse(ErrorConstants.FIELD_INVALID, + ErrorConstants.INVALID_PERIODIC_LIMIT_SIZE, + ErrorConstants.PATH_PERIOD_LIMIT); + } + + // Get the periodType from the limit + String periodType = limit.getAsString(ConsentExtensionConstants.PERIOD_TYPE); + + // If the periodType is already in the set, log an error and return a validation response + if (!periodTypes.add(periodType)) { + log.error(ErrorConstants.DUPLICATE_PERIOD_TYPE); + return ConsentManageUtil.getValidationResponse(ErrorConstants.FIELD_INVALID, + ErrorConstants.DUPLICATE_PERIOD_TYPE, + ErrorConstants.PATH_PERIOD_TYPE); + } + } + } else { + // If periodic limits key is missing, return an error + log.error(ErrorConstants.MISSING_PERIOD_LIMITS); + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_PERIOD_LIMITS); + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the Currency in periodic limits in the control parameters of a consent request. + * + * @param controlParameters The JSON object representing the control parameters of the consent request. + * @return A JSON object containing the validation response. + */ + public static JSONObject validateCurrencyPeriodicLimit(JSONObject controlParameters) { + + JSONObject validationResponse = new JSONObject(); + + JSONArray periodicLimits = (JSONArray) controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + JSONObject currencyValidationResponse = validateAmountCurrencyPeriodicLimits((JSONArray) periodicLimits, + ConsentExtensionConstants.CURRENCY, String.class); + if (!(Boolean.parseBoolean(currencyValidationResponse. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return currencyValidationResponse; + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the Amount in periodic limits in the control parameters of a consent request. + * + * @param controlParameters The JSON object representing the control parameters of the consent request. + * @return A JSON object containing the validation response. + */ + public static JSONObject validateAmountPeriodicLimit(JSONObject controlParameters) { + + JSONObject validationResponse = new JSONObject(); + + JSONArray periodicLimits = (JSONArray) controlParameters.get(ConsentExtensionConstants.PERIODIC_LIMITS); + + JSONObject amountValidationResponse = validateAmountCurrencyPeriodicLimits((JSONArray) periodicLimits, + ConsentExtensionConstants.AMOUNT, String.class); + if (!(Boolean.parseBoolean(amountValidationResponse. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return amountValidationResponse; + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the date-time parameters in the control parameters of a consent request. + * + * @param controlParameters The JSON object representing the control parameters of the consent request. + * @return A JSON object containing the validation response. If the date-time parameters are valid, + * it sets the "IS_VALID" field to true; otherwise, it contains an error response. + */ + public static JSONObject validateParameterDateTime(JSONObject controlParameters) { + JSONObject validationResponse = new JSONObject(); + + if (controlParameters.containsKey(ConsentExtensionConstants.VALID_TO_DATE_TIME)) { + + if (!ConsentManageUtil.isValid8601(controlParameters + .getAsString(ConsentExtensionConstants.VALID_TO_DATE_TIME))) { + log.error(" Date and Time is not in valid ISO 8601 format"); + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_VALID_TO_DATE_TIME); + } + + Object validToDateTimeRetrieval = controlParameters.get(ConsentExtensionConstants.VALID_TO_DATE_TIME); + JSONObject validToDateTimeValidationResponse = isValidDateTimeObject(validToDateTimeRetrieval); + if (!(Boolean.parseBoolean(validToDateTimeValidationResponse. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return validToDateTimeValidationResponse; + } + + String validToDateTimeString = controlParameters.getAsString(ConsentExtensionConstants.VALID_TO_DATE_TIME); + OffsetDateTime validToDateTime = OffsetDateTime.parse(validToDateTimeString); + + if (controlParameters.containsKey(ConsentExtensionConstants.VALID_FROM_DATE_TIME)) { + + if (!ConsentManageUtil.isValid8601(controlParameters + .getAsString(ConsentExtensionConstants.VALID_FROM_DATE_TIME))) { + log.error("Date and Time is not in valid ISO 8601 format"); + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_VALID_FROM_DATE_TIME); + } + + + Object validFromDateTimeRetrieval = controlParameters.get + (ConsentExtensionConstants.VALID_FROM_DATE_TIME); + JSONObject validFromDateTimeValidationResponse = isValidDateTimeObject(validFromDateTimeRetrieval); + if (!(Boolean.parseBoolean(validFromDateTimeValidationResponse. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return validFromDateTimeValidationResponse; + } + + String validFromoDateTimeString = controlParameters.getAsString + (ConsentExtensionConstants.VALID_FROM_DATE_TIME); + + OffsetDateTime validFromDateTime = OffsetDateTime.parse(validFromoDateTimeString); + OffsetDateTime currentDateTime = OffsetDateTime.now(validToDateTime.getOffset()); + + // If ValidToDateTime is older than current date OR ValidToDateTime is older than ValidFromDateTime, + // return error + if (!validFromDateTime.isBefore(currentDateTime) || !currentDateTime.isBefore(validToDateTime)) { + log.error(String.format("Invalid date-time range, " + + "validToDateTime: %s, validFromDateTime: %s, currentDateTime: %s", + validToDateTime, validFromDateTime, currentDateTime)); + + String errorMessage = String.format(ErrorConstants.DATE_INVALID_PARAMETER_MESSAGE); + + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } else { + log.error("validFromDateTime parameter is missing in the payload"); + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_VALID_FROM_DATE_TIME); + } + } else { + log.error("Missing validToDateTime parameter is missing in the payload"); + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_VALID_TO_DATE_TIME); + } + + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validator class to validate the payload of a variable recurring payment initiation. + * This method performs validation on the initiation payload for a variable recurring payment. + * It checks and validates the debtor account and creditor account information if present in the payload. + * If any validation fails, it returns a JSON object with details about the validation error. + * If the initiation payload passes all validations, the returned JSON object indicates a valid initiation. + * + * @param initiation The JSON object representing the variable recurring payment initiation payload. + * @return validationResponse + */ + public static JSONObject validateVRPInitiationPayload(JSONObject initiation) { + + JSONObject validationResponse = new JSONObject(); + + //Validate DebtorAccount + if (initiation.containsKey(ConsentExtensionConstants.DEBTOR_ACC)) { + + Object debtorAccount = initiation.get(ConsentExtensionConstants.DEBTOR_ACC); + + if (!isValidJSONObject(debtorAccount)) { + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, + "debtor account", "JSONObject"); + + return ConsentManageUtil.getValidationResponse(errorMessage); + } + + JSONObject validationResult = ConsentManageUtil.validateDebtorAccount((JSONObject) debtorAccount); + + if (!(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + log.error(validationResult.get(ConsentExtensionConstants.ERRORS)); + return validationResult; + } + + } else { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC); + } + + //Validate CreditorAccount + if (initiation.containsKey(ConsentExtensionConstants.CREDITOR_ACC)) { + + Object creditorAccount = initiation.get(ConsentExtensionConstants.CREDITOR_ACC); + + if (!isValidJSONObject(creditorAccount)) { + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, + "creditor account", "JSONObject"); + + return ConsentManageUtil.getValidationResponse(errorMessage); + } + + JSONObject validationResult = ConsentManageUtil.validateCreditorAccount((JSONObject) creditorAccount); + + if (!(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + log.error(validationResult.get(ConsentExtensionConstants.ERRORS)); + return validationResult; + } + + } else { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR_CREDITOR_ACC); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR); + } + + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + + /** + * Validates the presence of a specified key in a JSONObject (either the amount or the currency) + * and checks if the associated value is a non-empty string. + * + * @param parentObj The JSONObject to be validated. + * @param key The key to be checked for presence in the parentObj. + * @param expectedType The expected type of the value associated with the key. + * @param The expected type of the value associated with the key. + * @return true if the specified key is present in the parentObj and the associated value is a + * non-empty string. + */ + public static JSONObject validateJsonObjectKey(JSONObject parentObj, String key, Class expectedType) { + JSONObject validationResponse = new JSONObject(); + //Refractor removing passing class + if (parentObj != null) { + if (parentObj.containsKey(key)) { + Object value = parentObj.get(key); + + if (expectedType.isInstance(value)) { + if (value instanceof String && !((String) value).isEmpty()) { + if ("Amount".equals(key)) { + // For the "amount" key, try parsing as Double allowing letters + if (isDouble((String) value)) { + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } else { + String errorMessage = "The value of '" + key + "' is not a valid number"; + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } else { + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + } else { + String errorMessage = "The value of '" + key + "' is not a " + expectedType.getSimpleName() + + " or the value is empty"; + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } else { + String errorMessage = "The value of '" + key + "' is not of type " + expectedType.getSimpleName(); + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } else { + String errorMessage = "Mandatory parameter '" + key + "' is not present in payload"; + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } else { + String errorMessage = "parameter passed in is null"; + return ConsentManageUtil.getValidationResponse(errorMessage); + } + } + + /** + * Validates the presence of a specified key in a JSONArray (either the amount or the currency) + * in periodiclimits and checks if the associated value is a non-empty string. + * + * @param parentArray The JSONObject to be validated. + * @param key The key to be checked for presence in the parentObj. + * @param expectedType The expected type of the value associated with the key. + * @param The expected type of the value associated with the key. + * @return A JSONObject containing validation results for the entire array. + */ + public static JSONObject validateAmountCurrencyPeriodicLimits(JSONArray parentArray, String key, + Class expectedType) { + JSONObject validationResponse = new JSONObject(); + + if (parentArray != null) { + for (Object obj : parentArray) { + if (obj instanceof JSONObject) { + + JSONObject jsonObject = (JSONObject) obj; + JSONObject elementValidationResult = validateJsonObjectKey(jsonObject, key, expectedType); + + if (!(Boolean.parseBoolean(elementValidationResult.getAsString + (ConsentExtensionConstants.IS_VALID)))) { + return elementValidationResult; + } + } + } + } else { + String errorMessage = "parameter passed in is null"; + return ConsentManageUtil.getValidationResponse(errorMessage); + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + + /** + Checks if a given string can be parsed into a double value. + @param str The string to be checked. + @return True if the string can be parsed into a double value, false otherwise. + */ + private static boolean isDouble(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * Validates the consent initiation payload in the VRP request. + * + * @param request The JSONObject representing the VRP request. + * @return A JSONObject containing the validation response. + */ + public static JSONObject validateConsentInitiation(JSONObject request) { + + JSONObject validationResponse = new JSONObject(); + + JSONObject requestBody = (JSONObject) request; + JSONObject data = (JSONObject) requestBody.get(ConsentExtensionConstants.DATA); + + //Validate initiation in the VRP payload + if (data.containsKey(ConsentExtensionConstants.INITIATION)) { + + Object initiation = data.get(ConsentExtensionConstants.INITIATION); + + if (!isValidJSONObject(initiation)) { + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, + "initiation", "JSONObject"); + + return ConsentManageUtil.getValidationResponse(errorMessage); + } + + JSONObject initiationValidationResult = VRPConsentRequestValidator + .validateVRPInitiationPayload((JSONObject) initiation); + + if (!(Boolean.parseBoolean(initiationValidationResult.getAsString(ConsentExtensionConstants.IS_VALID)))) { + return initiationValidationResult; + } + } else { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR_INITIATION); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR_INITIATION); + } + + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the consent control parameters in the VRP request payload. + * + * @param request The JSONObject representing the VRP request. + * @return A JSONObject containing the validation response. + */ + public static JSONObject validateConsentControlParameters(JSONObject request) { + + JSONObject validationResponse = new JSONObject(); + + JSONObject requestBody = (JSONObject) request; + JSONObject data = (JSONObject) requestBody.get(ConsentExtensionConstants.DATA); + + //Validate the ControlParameter in the payload + if (data.containsKey(ConsentExtensionConstants.CONTROL_PARAMETERS)) { + + Object controlParameters = data.get(ConsentExtensionConstants.CONTROL_PARAMETERS); + + if (!isValidJSONObject(controlParameters)) { + String errorMessage = String.format(ErrorConstants.INVALID_PARAMETER_MESSAGE, + "control parameters", "JSONObject"); + + return ConsentManageUtil.getValidationResponse(errorMessage); + } + + JSONObject controlParameterValidationResult = + VRPConsentRequestValidator.validateControlParameters((JSONObject) + data.get(ConsentExtensionConstants.CONTROL_PARAMETERS)); + + if (!(Boolean.parseBoolean(controlParameterValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID)))) { + return controlParameterValidationResult; + } + } else { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR_CONTROL_PARAMETER); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR_CONTROL_PARAMETER); + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the risk information in the VRP request payload. + * + * @param request The JSONObject representing the VRP request. + * @return A JSONObject containing the validation response. + */ + public static JSONObject validateConsentRisk(JSONObject request) { + + JSONObject validationResponse = new JSONObject(); + + JSONObject requestBody = (JSONObject) request; + JSONObject data = (JSONObject) requestBody.get(ConsentExtensionConstants.DATA); + + // Check Risk key is mandatory + if (!requestBody.containsKey(ConsentExtensionConstants.RISK) || + !(requestBody.get(ConsentExtensionConstants.RISK) instanceof JSONObject + || ((JSONObject) requestBody.get(ConsentExtensionConstants.DATA)).isEmpty())) { + log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK); + return ConsentManageUtil.getValidationResponse(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK); + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } + + /** + * Validates the periodic alignment in the VRP request payload. + * + * @param limit The JSONObject representing the VRP request. + * @return A JSONObject containing the validation response. + */ + public static JSONObject validatePeriodAlignment(JSONObject limit) { + JSONObject validationResponse = new JSONObject(); + + if (limit.containsKey(ConsentExtensionConstants.PERIOD_ALIGNMENT)) { + Object periodAlignmentObj = limit.get(ConsentExtensionConstants.PERIOD_ALIGNMENT); + + if (periodAlignmentObj instanceof String && !((String) periodAlignmentObj).isEmpty()) { + String periodAlignment = (String) periodAlignmentObj; + + if (ConsentExtensionConstants.CONSENT.equals(periodAlignment) || + ConsentExtensionConstants.CALENDAR.equals(periodAlignment)) { + + validationResponse.put("isValid", true); + validationResponse.put("periodAlignment", periodAlignment); + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_PERIOD_ALIGNMENT); + } + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants. + PAYLOAD_FORMAT_ERROR_PERIODIC_LIMITS_ALIGNMENT); + } + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_PERIOD_ALIGNMENT); + } + return validationResponse; + } + + /** + * Validates the periodic type in the VRP request payload. + * + * @param limit The JSONObject representing the VRP request. + * @return A JSONObject containing the validation response. + */ + public static JSONObject validatePeriodType(JSONObject limit) { + JSONObject validationResponse = new JSONObject(); + + if (limit.containsKey(ConsentExtensionConstants.PERIOD_TYPE)) { + Object periodTypeObj = limit.get(ConsentExtensionConstants.PERIOD_TYPE); + + if (periodTypeObj instanceof String && !((String) periodTypeObj).isEmpty()) { + String periodType = (String) periodTypeObj; + + if (ConsentExtensionConstants.DAY.equals(periodType) || + ConsentExtensionConstants.WEEK.equals(periodType) || + ConsentExtensionConstants.FORTNIGHT.equals(periodType) || + ConsentExtensionConstants.MONTH.equals(periodType) || + ConsentExtensionConstants.HALF_YEAR.equals(periodType) || + ConsentExtensionConstants.YEAR.equals(periodType)) { + + validationResponse.put("isValid", true); + validationResponse.put("periodAlignment", periodType); + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_PERIOD_TYPE); + } + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants. + PAYLOAD_FORMAT_ERROR_PERIODIC_LIMITS_PERIOD_TYPE); + } + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_PERIOD_TYPE); + } + return validationResponse; + } + + /** + * Checks if the given Object is a JSONObject and the JSONObject is non-empty . + * + * @param value The Object to be validated. + * @return true if the object is a non-null and non-empty JSONObject. + */ + public static boolean isValidJSONObject(Object value) { + return value instanceof JSONObject && !((JSONObject) value).isEmpty(); + } + + /** + * Checks if the given object is a valid date-time string and it is non empty. + * + * @param value The object to be checked for a valid date-time format. + * @return True if the object is a non-empty string in ISO date-time format, false otherwise. + */ + private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ISO_DATE_TIME; + + public static JSONObject isValidDateTimeObject(Object value) { + JSONObject validationResponse = new JSONObject(); + + if (value instanceof String && !((String) value).isEmpty()) { + try { + String dateTimeString = (String) value; + dateTimeFormat.parse(dateTimeString); + } catch (DateTimeParseException e) { + return ConsentManageUtil.getValidationResponse(ErrorConstants.INVALID_DATE_TIME_FORMAT); + } + } else { + return ConsentManageUtil.getValidationResponse(ErrorConstants.MISSING_DATE_TIME_FORMAT); + } + validationResponse.put(ConsentExtensionConstants.IS_VALID, true); + return validationResponse; + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/ConsentManageUtil.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/ConsentManageUtil.java index 5506c011..f4297901 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/ConsentManageUtil.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/ConsentManageUtil.java @@ -24,6 +24,7 @@ import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionUtils; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; @@ -54,14 +55,16 @@ public class ConsentManageUtil { /** * Check whether valid Data object is provided. * - * @param initiation Data object in initiation payload + * @param initiationRequestbody Data object in initiation payload * @return whether the Data object is valid */ - public static JSONObject validateInitiationDataBody(JSONObject initiation) { + public static JSONObject validateInitiationDataBody(JSONObject initiationRequestbody) { JSONObject validationResponse = new JSONObject(); - if (!initiation.containsKey(ConsentExtensionConstants.DATA) || !(initiation.get(ConsentExtensionConstants.DATA) - instanceof JSONObject)) { + if (!initiationRequestbody.containsKey(ConsentExtensionConstants.DATA) || !(initiationRequestbody. + get(ConsentExtensionConstants.DATA) + instanceof JSONObject) || ((JSONObject) initiationRequestbody.get(ConsentExtensionConstants.DATA)) + .isEmpty()) { log.error(ErrorConstants.PAYLOAD_FORMAT_ERROR); return ConsentManageUtil.getValidationResponse(ErrorConstants.RESOURCE_INVALID_FORMAT, ErrorConstants.PAYLOAD_FORMAT_ERROR, ErrorConstants.PATH_REQUEST_BODY); @@ -77,7 +80,7 @@ public static JSONObject validateInitiationDataBody(JSONObject initiation) { * @param errorCode Error Code * @param errorMessage Error Message * @param errorPath Error Path - * @return + * @return JSONObject Validation response */ public static JSONObject getValidationResponse(String errorCode, String errorMessage, String errorPath) { JSONObject validationResponse = new JSONObject(); @@ -88,11 +91,27 @@ public static JSONObject getValidationResponse(String errorCode, String errorMes return validationResponse; } + /** + * Method to construct the consent manage validation response for vrp. + * + * @param errorMessage Error Message + * + * @return JSONObject Validation response + */ + public static JSONObject getValidationResponse(String errorMessage) { + JSONObject validationResponse = new JSONObject(); + + validationResponse.put(ConsentExtensionConstants.IS_VALID, false); + validationResponse.put(ConsentExtensionConstants.HTTP_CODE, ResponseStatus.BAD_REQUEST); + validationResponse.put(ConsentExtensionConstants.ERRORS, errorMessage); + return validationResponse; + } + /** * Method to validate debtor account. * * @param debtorAccount Debtor Account object - * @return + * @return JSONObject Validation response */ public static JSONObject validateDebtorAccount(JSONObject debtorAccount) { @@ -205,7 +224,7 @@ public static JSONObject validateDebtorAccount(JSONObject debtorAccount) { * Validate creditor account. * * @param creditorAccount Creditor Account object - * @return + * @return JSONObject Validation response */ public static JSONObject validateCreditorAccount(JSONObject creditorAccount) { @@ -320,8 +339,7 @@ public static void handleConsentManageDelete(ConsentManageData consentManageData Boolean shouldRevokeTokens; if (ConsentManageUtil.isConsentIdValid(consentId)) { try { - - ConsentResource consentResource = ConsentExtensionsDataHolder.getInstance().getConsentCoreService() + ConsentResource consentResource = ConsentServiceUtil.getConsentService() .getConsent(consentId, false); if (!consentResource.getClientID().equals(consentManageData.getClientId())) { @@ -361,7 +379,7 @@ public static void handleConsentManageDelete(ConsentManageData consentManageData * Utility class to check whether the Debtor Account Scheme name length. * * @param debtorAccSchemeName Debtor Account Scheme Name - * @return + * @return boolean Whether the Debtor Account Scheme name length is valid */ public static boolean validateDebtorAccSchemeNameLength(String debtorAccSchemeName) { if (log.isDebugEnabled()) { @@ -375,7 +393,7 @@ public static boolean validateDebtorAccSchemeNameLength(String debtorAccSchemeNa * Utility class to check whether the Debtor Account Scheme name matches with Enum values. * * @param debtorAccSchemeName Debtor Account Scheme Name - * @return + * @return boolean Whether the Debtor Account Scheme name is valid */ public static boolean isDebtorAccSchemeNameValid(String debtorAccSchemeName) { if (log.isDebugEnabled()) { @@ -394,7 +412,7 @@ public static boolean isDebtorAccSchemeNameValid(String debtorAccSchemeName) { * Utility class to check whether the Debtor Account Identification is valid. * * @param debtorAccIdentification Debtor Account Identification - * @return + * @return boolean Whether the Debtor Account Identification is valid */ public static boolean isDebtorAccIdentificationValid(String debtorAccIdentification) { if (log.isDebugEnabled()) { @@ -408,7 +426,7 @@ public static boolean isDebtorAccIdentificationValid(String debtorAccIdentificat * Utility class to check whether the Debtor Account Name is valid. * * @param debtorAccName Debtor Account Name - * @return + * @return boolean Whether the Debtor Account Name is valid */ public static boolean isDebtorAccNameValid(String debtorAccName) { if (log.isDebugEnabled()) { @@ -422,7 +440,7 @@ public static boolean isDebtorAccNameValid(String debtorAccName) { * Utility class to check whether the Debtor AccountSecondary Identification is valid. * * @param debtorAccSecondaryIdentification Debtor Account Secondary Identification - * @return + * @return boolean Whether the Debtor Account Secondary Identification is valid */ public static boolean isDebtorAccSecondaryIdentificationValid(String debtorAccSecondaryIdentification) { if (log.isDebugEnabled()) { @@ -456,6 +474,7 @@ private static boolean checkSortCodeSchemeNameAndIdentificationValidity(String s * Check whether the local instrument is supported. * * @param localInstrument Local Instrument value to validate + * @return Whether the local instrument is valid */ public static boolean validateLocalInstrument(String localInstrument) { ArrayList defaultLocalInstrumentList = new ArrayList<>(Arrays.asList( @@ -479,6 +498,7 @@ public static boolean validateLocalInstrument(String localInstrument) { * Check whether the amount is higher that the max instructed amount allowed by the bank. * * @param instructedAmount Instructed Amount to validate + * @return Whether the instructed amount is valid */ public static boolean validateMaxInstructedAmount(String instructedAmount) { //This is a mandatory configuration in open-banking.xml. Hence can't be null. @@ -493,11 +513,12 @@ public static boolean validateMaxInstructedAmount(String instructedAmount) { * * @param response Response of the request * @param createdConsent Consent response received from service layer - * @return + * @param consentManageData Request Details received + * @param type ConsentType + * @return JSONObject Initiation Response */ public static JSONObject getInitiationResponse(JSONObject response, DetailedConsentResource createdConsent, ConsentManageData consentManageData, String type) { - JSONObject dataObject = (JSONObject) response.get(ConsentExtensionConstants.DATA); dataObject.appendField(ConsentExtensionConstants.CONSENT_ID, createdConsent.getConsentID()); dataObject.appendField("CreationDateTime", convertEpochDateTime(createdConsent.getCreatedTime())); @@ -531,7 +552,9 @@ public static JSONObject getInitiationResponse(JSONObject response, DetailedCons * * @param receiptJSON Initiation of the request * @param consent Consent response received from service layer - * @return + * @param consentManageData Request Details received + * @param type ConsentType + * @return JSONObject Initiation Response */ public static JSONObject getInitiationRetrievalResponse(JSONObject receiptJSON, ConsentResource consent, ConsentManageData consentManageData, String type) { @@ -571,7 +594,7 @@ private static String convertEpochDateTime(long epochTime) { * @param consentId Consent ID * @param consentManageData Request Details recieved * @param type ConsentType - * @return + * @return Constructed Self Link */ public static String constructSelfLink(String consentId, ConsentManageData consentManageData, String type) { @@ -585,6 +608,9 @@ public static String constructSelfLink(String consentId, ConsentManageData conse } else if (ConsentExtensionConstants.FUNDSCONFIRMATIONS.equals(type)) { baseUrl = (String) parser.getConfiguration().get( ConsentExtensionConstants.COF_SELF_LINK); + } else if (ConsentExtensionConstants.VRP.equals(type)) { + baseUrl = (String) parser.getConfiguration().get( + ConsentExtensionConstants.VRP_SELF_LINK); } String requestPath = consentManageData.getRequestPath(); @@ -595,7 +621,7 @@ public static String constructSelfLink(String consentId, ConsentManageData conse * Validate the consent ID. * * @param consentId Consent Id to validate - * @return + * @return Whether the consent ID is valid */ public static boolean isConsentIdValid(String consentId) { return (consentId.length() == 36 && Pattern.matches(ConsentExtensionConstants.UUID_REGEX, consentId)); @@ -605,7 +631,7 @@ public static boolean isConsentIdValid(String consentId) { * Validate Expiration Date Time. * * @param expDateVal Expiration Date Time - * @return + * @return Whether the expiration date time is valid */ public static boolean isConsentExpirationTimeValid(String expDateVal) { if (expDateVal == null) { @@ -620,5 +646,19 @@ public static boolean isConsentExpirationTimeValid(String expDateVal) { return false; } } + /** + * Validate whether the date is a valid ISO 8601 format. + * @param dateValue Date value to validate + * @return Whether the date is a valid ISO 8601 format + */ + public static boolean isValid8601(String dateValue) { + try { + OffsetDateTime.parse(dateValue); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PaymentPayloadValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PaymentPayloadValidator.java index c8b08821..03e4782a 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PaymentPayloadValidator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PaymentPayloadValidator.java @@ -35,7 +35,7 @@ public class PaymentPayloadValidator { * * @param requestPath Request Path of the request * @param initiation Initiation Object of the request - * @return + * @return JSONObject Validation Response */ public static JSONObject validatePaymentInitiationPayload(String requestPath, JSONObject initiation) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PeriodicTypesEnum.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PeriodicTypesEnum.java new file mode 100644 index 00000000..5ec0d221 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/PeriodicTypesEnum.java @@ -0,0 +1,76 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.util; + +import java.time.LocalDate; + +/** + * This enum represents the different types of periods that can be used in the application. + * Each enum value is associated with a string representation and a method to calculate the divisor based + * on the period type. + * The divisor is used to convert other time units to this period type. + */ +public enum PeriodicTypesEnum { + + DAY("Day"), + + WEEK("Week"), + + FORTNIGHT("Fortnight"), + + MONTH("Month"), + + HALF_YEAR("Half-Year"), + + YEAR("Year"); + + private String value; + + PeriodicTypesEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + /** + * Returns the divisor based on the period type. + * + * @return the divisor based on the period type + */ + public int getDivisor() { + switch (this) { + case DAY: + return 1; + case WEEK: + return 7; + case FORTNIGHT: + return 14; + case MONTH: + return LocalDate.now().lengthOfMonth(); + case HALF_YEAR: + return LocalDate.now().isLeapYear() ? 181 : 180; + case YEAR: + return LocalDate.now().isLeapYear() ? 366 : 365; + default: + throw new IllegalArgumentException("Invalid PeriodType"); + } + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/ExpiredConsentStatusUpdateJob.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/ExpiredConsentStatusUpdateJob.java index 3e8c9942..fde76d8a 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/ExpiredConsentStatusUpdateJob.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/ExpiredConsentStatusUpdateJob.java @@ -56,8 +56,8 @@ public class ExpiredConsentStatusUpdateJob implements Job { /** * Method used to enforce periodic statues update of consents. * - * @param jobExecutionContext - * @throws JobExecutionException + * @param jobExecutionContext Job Execution Context + * @throws JobExecutionException if an error occurs while executing the job */ public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { try { @@ -70,6 +70,7 @@ public void execute(JobExecutionContext jobExecutionContext) throws JobExecution /** * Method to update statues of consents. + * @throws ConsentManagementException if an error occurs while updating the consent status */ public static void updateExpiredStatues() throws ConsentManagementException { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/RetentionDatabaseSyncJob.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/RetentionDatabaseSyncJob.java index dfb36c03..8ea9068e 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/RetentionDatabaseSyncJob.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/util/jobs/RetentionDatabaseSyncJob.java @@ -42,8 +42,8 @@ public class RetentionDatabaseSyncJob implements Job { /** * Method used to enforce sync the temporary retention data. * - * @param jobExecutionContext - * @throws JobExecutionException + * @param jobExecutionContext Job Execution Context + * @throws JobExecutionException if an error occurs while executing the job */ public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { @@ -56,6 +56,7 @@ public void execute(JobExecutionContext jobExecutionContext) throws JobExecution /** * Method to sync the temporary retention data. + * @throws ConsentManagementException if an error occurs while syncing the retention database */ public static void syncRetentionDatabase() throws ConsentManagementException { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/DefaultConsentValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/DefaultConsentValidator.java index 036c2ac4..0692ec13 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/DefaultConsentValidator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/DefaultConsentValidator.java @@ -1,13 +1,13 @@ /** * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). - * + *

* WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * 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 @@ -117,6 +117,9 @@ public void validate(ConsentValidateData consentValidateData, ConsentValidationR case ConsentExtensionConstants.FUNDSCONFIRMATIONS: validateFundsConfirmationSubmission(consentValidateData, receiptJSON, consentValidationResult); break; + case ConsentExtensionConstants.VRP: + validateVRPSubmission(consentValidateData, receiptJSON, consentValidationResult); + break; default: log.error(ErrorConstants.INVALID_CONSENT_TYPE); consentValidationResult.setErrorMessage(ErrorConstants.INVALID_CONSENT_TYPE); @@ -133,7 +136,7 @@ public void validate(ConsentValidateData consentValidateData, ConsentValidationR * @param consentValidationResult Validation result object to return */ private void validateAccountSubmission(ConsentValidateData consentValidateData, JSONObject receiptJSON, - ConsentValidationResult consentValidationResult) { + ConsentValidationResult consentValidationResult) { JSONArray permissions = (JSONArray) ((JSONObject) receiptJSON.get("Data")).get("Permissions"); @@ -154,7 +157,6 @@ private void validateAccountSubmission(ConsentValidateData consentValidateData, return; } - //Consent Status Validation if (!ConsentExtensionConstants.AUTHORIZED_STATUS .equalsIgnoreCase(consentValidateData.getComprehensiveConsent().getCurrentStatus())) { @@ -181,7 +183,7 @@ private void validateAccountSubmission(ConsentValidateData consentValidateData, * @param consentValidationResult Validation result object to return */ private void validatePaymentSubmission(ConsentValidateData consentValidateData, JSONObject initiationJson, - ConsentValidationResult consentValidationResult) { + ConsentValidationResult consentValidationResult) { DetailedConsentResource detailedConsentResource = consentValidateData.getComprehensiveConsent(); @@ -381,4 +383,126 @@ private static void validateFundsConfirmationSubmission(ConsentValidateData cons consentValidationResult.setValid(true); } + + /** + * Validate VRP Submission Request. + * + * @param consentValidateData Object with request data + * @param consentValidationResult Validation result object to return + */ + private void validateVRPSubmission(ConsentValidateData consentValidateData, JSONObject initiationJson, + ConsentValidationResult consentValidationResult) { + + DetailedConsentResource detailedConsentResource = consentValidateData.getComprehensiveConsent(); + + if (!ConsentExtensionConstants.AUTHORIZED_STATUS + .equals(consentValidateData.getComprehensiveConsent().getCurrentStatus())) { + log.error(ErrorConstants.VRP_CONSENT_STATUS_INVALID); + consentValidationResult.setErrorMessage(ErrorConstants.VRP_CONSENT_STATUS_INVALID); + consentValidationResult.setErrorCode(ErrorConstants.RESOURCE_INVALID_CONSENT_STATUS); + consentValidationResult.setHttpCode(HttpStatus.SC_BAD_REQUEST); + return; + } + + // Check if requested consent ID matches to initiation consent ID. + if (consentValidateData.getConsentId() == null || detailedConsentResource.getConsentID() == null || + !consentValidateData.getConsentId().equals(detailedConsentResource.getConsentID())) { + log.error(ErrorConstants.MSG_INVALID_CONSENT_ID); + consentValidationResult.setErrorMessage(ErrorConstants.MSG_INVALID_CONSENT_ID); + consentValidationResult.setErrorCode(ErrorConstants.RESOURCE_CONSENT_MISMATCH); + consentValidationResult.setHttpCode(HttpStatus.SC_BAD_REQUEST); + return; + } + + JSONObject submissionJson = consentValidateData.getPayload(); + + JSONObject dataValidationResults = VRPSubmissionPayloadValidator.validateSubmissionData(submissionJson); + if (!Boolean.parseBoolean(dataValidationResults. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(dataValidationResults, + consentValidationResult); + return; + } + + JSONObject submissionData = (JSONObject) submissionJson.get(ConsentExtensionConstants.DATA); + + JSONObject initiationParameterValidationResults = VRPSubmissionPayloadValidator. + validateInitiationParameter(submissionData); + if (!Boolean.parseBoolean(initiationParameterValidationResults. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(initiationParameterValidationResults, + consentValidationResult); + return; + } + + JSONObject instructionParameterValidationResults = VRPSubmissionPayloadValidator. + validateInstructionParameter(submissionData); + if (!Boolean.parseBoolean(instructionParameterValidationResults. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(instructionParameterValidationResults, + consentValidationResult); + return; + } + + // Check if requested consent ID in the body to initiation consent ID. + if (!submissionData.containsKey(ConsentExtensionConstants.CONSENT_ID) || + !(submissionData.get(ConsentExtensionConstants.CONSENT_ID) instanceof String) || + !submissionData.get(ConsentExtensionConstants.CONSENT_ID) + .equals(detailedConsentResource.getConsentID())) { + log.error(ErrorConstants.INVALID_REQUEST_CONSENT_ID); + consentValidationResult.setErrorMessage(ErrorConstants.INVALID_REQUEST_CONSENT_ID); + consentValidationResult.setErrorCode(ErrorConstants.RESOURCE_CONSENT_MISMATCH); + consentValidationResult.setHttpCode(HttpStatus.SC_BAD_REQUEST); + return; + } + + JSONObject dataObject = (JSONObject) initiationJson.get(ConsentExtensionConstants.DATA); + JSONObject requestInitiation = (JSONObject) dataObject.get(ConsentExtensionConstants.INITIATION); + JSONObject submissionInitiation = (JSONObject) submissionData.get(ConsentExtensionConstants.INITIATION); + JSONObject submissionInstruction = (JSONObject) submissionData.get(ConsentExtensionConstants.INSTRUCTION); + + JSONObject initiationValidationResult = VRPSubmissionPayloadValidator + .validateInitiation(submissionInitiation, requestInitiation); + + if (!Boolean.parseBoolean(initiationValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(initiationValidationResult, + consentValidationResult); + return; + } + + // Here the requestInitiation is passed as a parameter inorder to compare the creditor account in + // the initiation payload present under the initiation parameter, with the submission payload present under the + // instruction parameter. + JSONObject instructionValidationResult = VRPSubmissionPayloadValidator. + validateInstruction(submissionInstruction, requestInitiation); + + if (!Boolean.parseBoolean(instructionValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(instructionValidationResult, + consentValidationResult); + return; + } + + JSONObject riskParameterValidationResults = VRPSubmissionPayloadValidator.validateRiskParameter(submissionJson); + if (!Boolean.parseBoolean(riskParameterValidationResults. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(riskParameterValidationResults, + consentValidationResult); + return; + } + + JSONObject initiationRisk = (JSONObject) initiationJson.get(ConsentExtensionConstants.RISK); + JSONObject submissionRisk = (JSONObject) submissionJson.get(ConsentExtensionConstants.RISK); + JSONObject riskValidationResult = VRPSubmissionPayloadValidator.validateRisk(submissionRisk, + initiationRisk); + + if (!Boolean.parseBoolean(riskValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + ConsentValidatorUtil.setErrorMessageForConsentValidationResult(riskValidationResult, + consentValidationResult); + return; + } + consentValidationResult.setValid(true); + } } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/PaymentSubmissionPayloadValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/PaymentSubmissionPayloadValidator.java index fd187814..421a13b3 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/PaymentSubmissionPayloadValidator.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/PaymentSubmissionPayloadValidator.java @@ -34,7 +34,7 @@ public class PaymentSubmissionPayloadValidator { * * @param submission Submission Request * @param initiation Initiation Request - * @return + * @return JSONObject Validation Response */ public JSONObject validateInitiation(JSONObject submission, JSONObject initiation) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/VRPSubmissionPayloadValidator.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/VRPSubmissionPayloadValidator.java new file mode 100644 index 00000000..d6431f1d --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/impl/VRPSubmissionPayloadValidator.java @@ -0,0 +1,516 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.validate.impl; + +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.validate.util.ConsentValidatorUtil; +import net.minidev.json.JSONObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Class for validating VRP submission request. + */ +public class VRPSubmissionPayloadValidator { + private static final Log log = LogFactory.getLog(VRPSubmissionPayloadValidator.class); + + /** + * Validates the initiation parameters between the initiation of submission request and the initiation parameters + * of consent initiation request. + * + * @param initiationOfSubmission The initiation parameters from the submission request. + * @param initiationParameterOfConsentInitiation The initiation parameters from the consent initiation request. + * @return A JSONObject indicating the validation result. It contains a boolean value under the key + * ConsentExtensionConstants.IS_VALID_PAYLOAD, indicating whether the payload is valid. If the + * validation fails, it returns a JSONObject containing error details with keys defined in ErrorConstants. + */ + public static JSONObject validateInitiation(JSONObject initiationOfSubmission, + JSONObject initiationParameterOfConsentInitiation) { + + if (initiationOfSubmission != null && initiationParameterOfConsentInitiation != null) { + + + + //Validate Creditor Account + if ((!initiationOfSubmission.containsKey(ConsentExtensionConstants.CREDITOR_ACC) && + initiationParameterOfConsentInitiation.containsKey(ConsentExtensionConstants.CREDITOR_ACC)) || + (initiationOfSubmission.containsKey(ConsentExtensionConstants.CREDITOR_ACC) && + !initiationParameterOfConsentInitiation. + containsKey(ConsentExtensionConstants.CREDITOR_ACC))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.CREDITOR_ACC_NOT_FOUND); + } else if (initiationOfSubmission.containsKey(ConsentExtensionConstants.CREDITOR_ACC) && + initiationParameterOfConsentInitiation.containsKey(ConsentExtensionConstants.CREDITOR_ACC)) { + + Object submissionCreditorAccounts = initiationOfSubmission. + get(ConsentExtensionConstants.CREDITOR_ACC); + Object consentInitiationCreditorAccounts = initiationParameterOfConsentInitiation. + get(ConsentExtensionConstants.CREDITOR_ACC); + + if (submissionCreditorAccounts instanceof JSONObject && + consentInitiationCreditorAccounts instanceof JSONObject) { + JSONObject submissionCreditorAccount = (JSONObject) initiationOfSubmission. + get(ConsentExtensionConstants.CREDITOR_ACC); + JSONObject consentInitiationCreditorAccount = (JSONObject) + initiationParameterOfConsentInitiation.get(ConsentExtensionConstants.CREDITOR_ACC); + + JSONObject creditorAccValidationResult = ConsentValidatorUtil. + validateCreditorAcc(submissionCreditorAccount, consentInitiationCreditorAccount); + if (!Boolean.parseBoolean(creditorAccValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + return creditorAccValidationResult; + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INITIATION_CREDITOR_ACC_NOT_JSON_ERROR); + } + } + + //Validate Debtor Account + // This code if condition checks whether the debtor account parameter is present in both the request + // payloads (Initiation and the submission payloads) since both the payloads as to be equal. + if ((!initiationOfSubmission.containsKey(ConsentExtensionConstants.DEBTOR_ACC) && + initiationParameterOfConsentInitiation.containsKey(ConsentExtensionConstants.DEBTOR_ACC)) || + (initiationOfSubmission.containsKey(ConsentExtensionConstants.DEBTOR_ACC) && + !initiationParameterOfConsentInitiation. + containsKey(ConsentExtensionConstants.DEBTOR_ACC))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.DEBTOR_ACC_NOT_FOUND); + } else if (initiationOfSubmission.containsKey(ConsentExtensionConstants.DEBTOR_ACC) && + initiationParameterOfConsentInitiation.containsKey(ConsentExtensionConstants.DEBTOR_ACC)) { + + Object submissionDebtorAccounts = initiationOfSubmission + .get(ConsentExtensionConstants.DEBTOR_ACC); + Object consentInitiationDebtorAccounts = initiationParameterOfConsentInitiation + .get(ConsentExtensionConstants.DEBTOR_ACC); + + if (submissionDebtorAccounts instanceof JSONObject && + consentInitiationDebtorAccounts instanceof JSONObject) { + JSONObject submissionDebtorAccount = (JSONObject) initiationOfSubmission + .get(ConsentExtensionConstants.DEBTOR_ACC); + JSONObject consentInitiationDebtorAccount = (JSONObject) initiationParameterOfConsentInitiation + .get(ConsentExtensionConstants.DEBTOR_ACC); + + JSONObject debtorAccValidationResult = ConsentValidatorUtil. + validateDebtorAcc(submissionDebtorAccount, consentInitiationDebtorAccount); + if (!Boolean.parseBoolean(debtorAccValidationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + return debtorAccValidationResult; + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.DEBTOR_ACC_NOT_JSON_ERROR); + } + } + + if ((!initiationOfSubmission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && initiationParameterOfConsentInitiation.containsKey(ConsentExtensionConstants.REMITTANCE_INFO)) || + (initiationOfSubmission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && !initiationParameterOfConsentInitiation. + containsKey(ConsentExtensionConstants.REMITTANCE_INFO))) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.REMITTANCE_INFO_NOT_FOUND); + } else if (initiationOfSubmission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && initiationParameterOfConsentInitiation. + containsKey(ConsentExtensionConstants.REMITTANCE_INFO)) { + + Object remittanceInformationSubmission = initiationOfSubmission + .get(ConsentExtensionConstants.REMITTANCE_INFO); + Object remittanceInformationInitiation = initiationParameterOfConsentInitiation + .get(ConsentExtensionConstants.REMITTANCE_INFO); + + if (remittanceInformationSubmission instanceof JSONObject && + remittanceInformationInitiation instanceof JSONObject) { + JSONObject remittanceInformationSub = (JSONObject) initiationOfSubmission + .get(ConsentExtensionConstants.REMITTANCE_INFO); + JSONObject remittanceInformationInit = (JSONObject) initiationParameterOfConsentInitiation + .get(ConsentExtensionConstants.REMITTANCE_INFO); + + JSONObject validateRemittanceInfoResult = VRPSubmissionPayloadValidator.validateRemittanceInfo + (remittanceInformationSub, remittanceInformationInit); + if (!Boolean.parseBoolean(validateRemittanceInfoResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + return validateRemittanceInfoResult; + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INITIATION_REMITTANCE_INFO_NOT_JSON_ERROR); + } + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INVALID_PARAMETER); + } + + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Validates the instruction between submission and initiation JSONObjects. + * + * @param submission The submission JSONObject from submission request. + * @param initiation The initiation JSONObject from initiation request, here we consider the initiation parameter + * since the creditor account from the initiation request need to be retrieved. + * @return A JSONObject indicating the validation result. It contains a boolean value under the key + * ConsentExtensionConstants.IS_VALID_PAYLOAD, indicating whether the payload is valid. If the + * validation fails, it returns a JSONObject containing error details with keys defined in ErrorConstants. + */ + public static JSONObject validateInstruction(JSONObject submission, + JSONObject initiation) { + + if (submission != null && initiation != null) { + + if (!submission.containsKey(ConsentExtensionConstants.INSTRUCTED_AMOUNT)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INSTRUCTED_AMOUNT_NOT_FOUND); + } else { + Object instructedAmountObject = submission.get(ConsentExtensionConstants.INSTRUCTED_AMOUNT); + + if (isValidJSONObject(instructedAmountObject)) { + JSONObject instructedAmount = (JSONObject) instructedAmountObject; + if (!instructedAmount.containsKey(ConsentExtensionConstants.AMOUNT)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INSTRUCTED_AMOUNT_AMOUNT_NOT_FOUND); + } else { + Object amountValue = instructedAmount.get(ConsentExtensionConstants.AMOUNT); + if (!isValidString(amountValue)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTED_AMOUNT_NOT_STRING); + } + + if (!instructedAmount.containsKey(ConsentExtensionConstants.CURRENCY)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INSTRUCTED_AMOUNT_CURRENCY_NOT_FOUND); + } else { + Object currencyValue = instructedAmount.get(ConsentExtensionConstants.CURRENCY); + if (!isValidString(currencyValue)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTED_AMOUNT_CURRENCY_NOT_STRING); + } + } + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTED_AMOUNT_NOT_JSON_ERROR); + } + } + + //Validate Creditor Account + JSONObject validateCreditorAccResult = VRPSubmissionPayloadValidator.validateCreditorAcc + (submission, initiation); + if (!Boolean.parseBoolean(validateCreditorAccResult. + get(ConsentExtensionConstants.IS_VALID_PAYLOAD).toString())) { + return validateCreditorAccResult; + } + + if (submission.containsKey(ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION)) { + Object value = submission.get(ConsentExtensionConstants.INSTRUCTION_IDENTIFICATION); + + // Check if the instruction_identification is an instance of a string + if (!isValidString(value)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INVALID_SUBMISSION_TYPE); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INSTRUCTION_IDENTIFICATION_NOT_FOUND); + } + + if (submission.containsKey(ConsentExtensionConstants.END_TO_END_IDENTIFICATION)) { + Object endToEndIdentificationValue = submission. + get(ConsentExtensionConstants.END_TO_END_IDENTIFICATION); + if (!isValidString(endToEndIdentificationValue)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INVALID_END_TO_END_IDENTIFICATION_TYPE); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.END_TO_END_IDENTIFICATION_PARAMETER_NOT_FOUND); + } + + if ((!submission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && initiation.containsKey(ConsentExtensionConstants.REMITTANCE_INFO)) || + (submission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && !initiation.containsKey(ConsentExtensionConstants.REMITTANCE_INFO))) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.REMITTANCE_INFO_NOT_FOUND); + } else if (submission.containsKey(ConsentExtensionConstants.REMITTANCE_INFO) + && initiation.containsKey(ConsentExtensionConstants.REMITTANCE_INFO)) { + Object remittanceInformationSubmission = submission + .get(ConsentExtensionConstants.REMITTANCE_INFO); + Object remittanceInformationInitiation = initiation + .get(ConsentExtensionConstants.REMITTANCE_INFO); + + if (remittanceInformationSubmission instanceof JSONObject && + remittanceInformationInitiation instanceof JSONObject) { + JSONObject remittanceInformationSub = (JSONObject) submission + .get(ConsentExtensionConstants.REMITTANCE_INFO); + JSONObject remittanceInformationInit = (JSONObject) initiation + .get(ConsentExtensionConstants.REMITTANCE_INFO); + + JSONObject remittanceInfoValidationResult = VRPSubmissionPayloadValidator.validateRemittanceInfo + (remittanceInformationSub, remittanceInformationInit); + if ((!Boolean.parseBoolean(remittanceInfoValidationResult. + get(ConsentExtensionConstants.IS_VALID_PAYLOAD).toString()))) { + return remittanceInfoValidationResult; + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTION_REMITTANCE_INFO_NOT_JSON_ERROR); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INVALID_PARAMETER); + } + } + + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Validates the remittance information between two remittance information JSONObjects. + * + * @param remittanceInformationSub The remittance information from the submission request. + * @param remittanceInformationInit The remittance information from the initiation request. + * @return A JSONObject indicating the validation result. It contains a boolean value under the key + * ConsentExtensionConstants.IS_VALID_PAYLOAD, indicating whether the payload is valid. If the + * validation fails, it returns a JSONObject containing error details with keys defined in ErrorConstants. + */ + public static JSONObject validateRemittanceInfo(JSONObject remittanceInformationSub, + JSONObject remittanceInformationInit) { + + if (!ConsentValidatorUtil.compareOptionalParameter( + remittanceInformationSub.getAsString(ConsentExtensionConstants.REFERENCE), + remittanceInformationInit.getAsString(ConsentExtensionConstants.REFERENCE))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.REMITTANCE_INFO_MISMATCH); + } + + if (!ConsentValidatorUtil.compareOptionalParameter( + remittanceInformationSub.getAsString(ConsentExtensionConstants.UNSTRUCTURED), + remittanceInformationInit.getAsString(ConsentExtensionConstants.UNSTRUCTURED))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.REMITTANCE_UNSTRUCTURED_MISMATCH); + } + + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Validates the risk parameters between the risk of submission and the risk of initiation JSONObjects. + * + * @param riskOfSubmission The risk parameters from the submission. + * @param riskOfInitiation The risk parameters from the initiation. + * @return A JSONObject indicating the validation result. It contains a boolean value under the key + * ConsentExtensionConstants.IS_VALID_PAYLOAD, indicating whether the payload is valid. If the + * validation fails, it returns a JSONObject containing error details with keys defined in ErrorConstants. + */ + public static JSONObject validateRisk(JSONObject riskOfSubmission, + JSONObject riskOfInitiation) { + + if (!ConsentValidatorUtil.compareOptionalParameter( + riskOfSubmission.getAsString(ConsentExtensionConstants.CONTEXT_CODE), + riskOfInitiation.getAsString(ConsentExtensionConstants.CONTEXT_CODE))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.RISK_PARAMETER_MISMATCH); + } + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * This method validates whether the risk parameter is present in the request and validates the risk parameter is an + * instance of JSONObject. + * + * @param submissionJson + * @return validationResult + */ + public static JSONObject validateRiskParameter(JSONObject submissionJson) { + + //Validate RISK + if (submissionJson.containsKey(ConsentExtensionConstants.RISK)) { + + Object dataObject = submissionJson.get(ConsentExtensionConstants.RISK); + // Check if the risk is valid JSON Object + if (!isValidJSONObject(dataObject)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.RISK_NOT_JSON_ERROR); + } + } else { + log.error(ErrorConstants.RISK_NOT_FOUND); + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.RISK_NOT_FOUND); + } + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Checks if the given Object is a JSONObject and the JSONObject is non-empty , and it is an instance of a string. + * + * @param value The Object to be validated. + * @return true if the object is a non-null and non-empty JSONObject. + */ + public static boolean isValidString(Object value) { + return value instanceof String; + } + + /** + * Validates initiation parameter in the submission data. + * + * @param submissionData The JSONObject containing submission data. + * @return A JSONObject indicating the validation result. + */ + public static JSONObject validateInitiationParameter(JSONObject submissionData) { + + if (submissionData.containsKey(ConsentExtensionConstants.INITIATION)) { + + Object dataObject = submissionData.get(ConsentExtensionConstants.INITIATION); + + if (!isValidJSONObject(dataObject)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INITIATION_NOT_JSON); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INITIATION_NOT_FOUND); + } + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Validates instruction parameter in the submission data. + * + * @param submissionData The JSONObject containing submission data. + * @return A JSONObject indicating the validation result. + */ + public static JSONObject validateInstructionParameter(JSONObject submissionData) { + + if (submissionData.containsKey(ConsentExtensionConstants.INSTRUCTION)) { + + Object dataObject = submissionData.get(ConsentExtensionConstants.INSTRUCTION); + if (!isValidJSONObject(dataObject)) { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTION_NOT_JSON); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.INSTRUCTION_NOT_FOUND); + } + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Extracts submission data from a JSONObject. + * + * @param submissionJson The JSONObject containing submission data. + * @return A JSONObject indicating the validation result. + */ + public static JSONObject validateSubmissionData(JSONObject submissionJson) { + + if (!submissionJson.containsKey(ConsentExtensionConstants.DATA) && + !(submissionJson.get(ConsentExtensionConstants.DATA) instanceof JSONObject)) { + log.error(ErrorConstants.DATA_NOT_FOUND); + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.DATA_NOT_FOUND); + } + JSONObject validationResult = new JSONObject(); + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } + + /** + * Checks if the given object is a valid JSONObject. + * + * @param value The object to be checked. + * @return true if the object is a JSONObject, otherwise false. + */ + public static boolean isValidJSONObject(Object value) { + return value instanceof JSONObject; + } + + /** + * Validates the creditor account parameter between the creditor account of submission under instruction parameter + * and the creditor account of initiation JSONObjects. + * + * @param submission The creditor account parameters from the submission. + * @param initiation The creditor account parameters from the initiation. + * @return A JSONObject indicating the validation result. It contains a boolean value under the key + * ConsentExtensionConstants.IS_VALID_PAYLOAD, indicating whether the payload is valid. If the + * validation fails, it returns a JSONObject containing error details with keys defined in ErrorConstants. + */ + public static JSONObject validateCreditorAcc(JSONObject submission, + JSONObject initiation) { + JSONObject validationResult = new JSONObject(); + + if (submission.containsKey(ConsentExtensionConstants.CREDITOR_ACC)) { + // If the CreditorAccount was not specified in the consent initiation,the CreditorAccount must be specified + // in the instruction present in the submission payload. + if (!initiation.containsKey(ConsentExtensionConstants.CREDITOR_ACC)) { + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + } else { + Object submissionCreditorAccounts = submission.get(ConsentExtensionConstants.CREDITOR_ACC); + Object consentInitiationCreditorAccounts = initiation.get(ConsentExtensionConstants.CREDITOR_ACC); + + if (submissionCreditorAccounts instanceof JSONObject && + consentInitiationCreditorAccounts instanceof JSONObject) { + JSONObject submissionCreditorAccount = (JSONObject) submission. + get(ConsentExtensionConstants.CREDITOR_ACC); + JSONObject consentInitiationCreditorAccount = (JSONObject) initiation. + get(ConsentExtensionConstants.CREDITOR_ACC); + + JSONObject creditorAccValidationResult = ConsentValidatorUtil. + validateCreditorAcc(submissionCreditorAccount, consentInitiationCreditorAccount); + if (!Boolean.parseBoolean(validationResult. + getAsString(ConsentExtensionConstants.IS_VALID_PAYLOAD))) { + return creditorAccValidationResult; + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_INVALID, + ErrorConstants.INSTRUCTION_CREDITOR_ACC_NOT_JSON_ERROR); + } + } + } else { + // Creditor account present under the instruction in the submission request + // is considered to be a mandatory parameter + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.CREDITOR_ACC_NOT_FOUND); + } + + validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); + return validationResult; + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/util/ConsentValidatorUtil.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/util/ConsentValidatorUtil.java index f5ba4d9e..a80d3ba6 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/util/ConsentValidatorUtil.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/main/java/com/wso2/openbanking/accelerator/consent/extensions/validate/util/ConsentValidatorUtil.java @@ -22,10 +22,12 @@ import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; import com.wso2.openbanking.accelerator.consent.extensions.common.ResponseStatus; +import com.wso2.openbanking.accelerator.consent.extensions.validate.model.ConsentValidationResult; import net.minidev.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; import java.time.OffsetDateTime; import java.time.format.DateTimeParseException; @@ -44,7 +46,7 @@ public class ConsentValidatorUtil { * * @param str1 First String to validate * @param str2 Second String to validate - * @return + * @return Whether mandatory parameters are same */ public static boolean compareMandatoryParameter(String str1, String str2) { @@ -57,7 +59,7 @@ public static boolean compareMandatoryParameter(String str1, String str2) { * * @param errorCode Error Code * @param errorMessage Error Message - * @return + * @return Validation Result */ public static JSONObject getValidationResult(String errorCode, String errorMessage) { @@ -69,10 +71,30 @@ public static JSONObject getValidationResult(String errorCode, String errorMessa return validationResult; } + + + /** + * Populates the provided consent validation result object with error information. + * + * @param errorResult the JSONObject containing error details, specifically error message and error code + * @param consentValidationResult the ConsentValidationResult object to be updated with error details + * + */ + public static void setErrorMessageForConsentValidationResult(JSONObject errorResult + , ConsentValidationResult consentValidationResult) { + + String errorMessage = errorResult.getAsString(ConsentExtensionConstants.ERROR_MESSAGE); + String errorCode = errorResult.getAsString(ConsentExtensionConstants.ERROR_CODE); + + consentValidationResult.setErrorMessage(errorMessage); + consentValidationResult.setErrorCode(errorCode); + consentValidationResult.setHttpCode(HttpStatus.SC_BAD_REQUEST); + } + /** * Method to construct the success validation result. * - * @return + * @return Validation Result */ public static JSONObject getSuccessValidationResult() { @@ -91,51 +113,50 @@ public static JSONObject getSuccessValidationResult() { */ public static JSONObject validateCreditorAcc(JSONObject subCreditorAccount, JSONObject initCreditorAccount) { - if (subCreditorAccount.containsKey(ConsentExtensionConstants.SCHEME_NAME)) { - if (StringUtils.isEmpty(subCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME)) || - !ConsentValidatorUtil.compareMandatoryParameter( - subCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME), - initCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME))) { + if (subCreditorAccount.containsKey(ConsentExtensionConstants.SCHEME_NAME)) { + if (StringUtils.isEmpty(subCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME)) || + !ConsentValidatorUtil.compareMandatoryParameter( + subCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME), + initCreditorAccount.getAsString(ConsentExtensionConstants.SCHEME_NAME))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.CREDITOR_ACC_SCHEME_NAME_MISMATCH); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.CREDITOR_ACC_SCHEME_NAME_NOT_FOUND); + } - return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, - ErrorConstants.CREDITOR_ACC_SCHEME_NAME_MISMATCH); + if (subCreditorAccount.containsKey(ConsentExtensionConstants.IDENTIFICATION)) { + if (StringUtils.isEmpty(subCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION)) || + !ConsentValidatorUtil.compareMandatoryParameter( + subCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION), + initCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION))) { + + return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.CREDITOR_ACC_IDENTIFICATION_MISMATCH); + } + } else { + return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, + ErrorConstants.CREDITOR_ACC_IDENTIFICATION_NOT_FOUND); } - } else { - return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, - ErrorConstants.CREDITOR_ACC_SCHEME_NAME_NOT_FOUND); - } - if (subCreditorAccount.containsKey(ConsentExtensionConstants.IDENTIFICATION)) { - if (StringUtils.isEmpty(subCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION)) || - !ConsentValidatorUtil.compareMandatoryParameter( - subCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION), - initCreditorAccount.getAsString(ConsentExtensionConstants.IDENTIFICATION))) { + if (!ConsentValidatorUtil + .compareOptionalParameter(subCreditorAccount.getAsString(ConsentExtensionConstants.NAME), + initCreditorAccount.getAsString(ConsentExtensionConstants.NAME))) { return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, - ErrorConstants.CREDITOR_ACC_IDENTIFICATION_MISMATCH); + ErrorConstants.CREDITOR_ACC_NAME_MISMATCH); } - } else { - return ConsentValidatorUtil.getValidationResult(ErrorConstants.FIELD_MISSING, - ErrorConstants.CREDITOR_ACC_IDENTIFICATION_NOT_FOUND); - } - if (!ConsentValidatorUtil - .compareOptionalParameter(subCreditorAccount.getAsString(ConsentExtensionConstants.NAME), - initCreditorAccount.getAsString(ConsentExtensionConstants.NAME))) { - - return ConsentValidatorUtil.getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, - ErrorConstants.CREDITOR_ACC_NAME_MISMATCH); - } - - if (!ConsentValidatorUtil.compareOptionalParameter(subCreditorAccount - .getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION), - initCreditorAccount.getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION))) { - - return ConsentValidatorUtil - .getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, - ErrorConstants.CREDITOR_ACC_SEC_IDENTIFICATION_MISMATCH); - } + if (!ConsentValidatorUtil.compareOptionalParameter(subCreditorAccount + .getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION), + initCreditorAccount.getAsString(ConsentExtensionConstants.SECONDARY_IDENTIFICATION))) { + return ConsentValidatorUtil + .getValidationResult(ErrorConstants.RESOURCE_CONSENT_MISMATCH, + ErrorConstants.CREDITOR_ACC_SEC_IDENTIFICATION_MISMATCH); + } JSONObject validationResult = new JSONObject(); validationResult.put(ConsentExtensionConstants.IS_VALID_PAYLOAD, true); @@ -146,7 +167,7 @@ public static JSONObject validateCreditorAcc(JSONObject subCreditorAccount, JSON * * @param str1 First String to validate * @param str2 Second String to validate - * @return + * @return Whether optional parameters are same */ public static boolean compareOptionalParameter(String str1, String str2) { @@ -240,7 +261,7 @@ public static List getCOFAPIPathRegexArray() { * Util method to validate the Confirmation of Funds request URI. * * @param uri Request URI - * @return + * @return Whether URI is valid */ public static boolean isCOFURIValid(String uri) { @@ -259,8 +280,8 @@ public static boolean isCOFURIValid(String uri) { * Validate whether consent is expired. * * @param expDateVal Expiration Date Time - * @return - * @throws ConsentException + * @return Whether consent is expired + * @throws ConsentException if an error occurs while parsing expiration date */ public static boolean isConsentExpired(String expDateVal) throws ConsentException { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/persistence/flow/ConsentPersistStepTests.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/persistence/flow/ConsentPersistStepTests.java new file mode 100644 index 00000000..db75703c --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/persistence/flow/ConsentPersistStepTests.java @@ -0,0 +1,258 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.authorize.vrp.persistence.flow; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.DefaultConsentPersistStep; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentPersistData; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentAuthorizeTestConstants; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockObjectFactory; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.powermock.api.mockito.PowerMockito.when; + +/** + * Test class for Consent Persistence. + */ +@PrepareForTest({OpenBankingConfigParser.class, ConsentServiceUtil.class}) +@PowerMockIgnore({"com.wso2.openbanking.accelerator.consent.extensions.common.*", "net.minidev.*", + "jdk.internal.reflect.*"}) +public class ConsentPersistStepTests { + + @Mock + OpenBankingConfigParser openBankingConfigParserMock; + @Mock + private static DefaultConsentPersistStep consentPersistStep; + @Mock + private static ConsentPersistData consentPersistDataMock; + @Mock + private static ConsentData consentDataMock; + @Mock + private static ConsentResource consentResourceMock; + @Mock + ConsentCoreServiceImpl consentCoreServiceMock; + private static Map configMap; + JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + + @BeforeClass + public void initTest() throws ReflectiveOperationException { + + MockitoAnnotations.initMocks(this); + + consentPersistStep = new DefaultConsentPersistStep(); + consentPersistDataMock = Mockito.mock(ConsentPersistData.class); + consentDataMock = Mockito.mock(ConsentData.class); + consentResourceMock = Mockito.mock(ConsentResource.class); + consentCoreServiceMock = Mockito.mock(ConsentCoreServiceImpl.class); + + configMap = new HashMap<>(); + configMap.put("ErrorURL", "https://localhost:8243/error"); + + //to execute util class initialization + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + } + + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new PowerMockObjectFactory(); + } + + @BeforeMethod + public void initMethod() { + + openBankingConfigParserMock = Mockito.mock(OpenBankingConfigParser.class); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + } + + @Test(priority = 1, expectedExceptions = ConsentException.class) + public void testConsentPersistWithoutConsentId() { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 3, expectedExceptions = ConsentException.class) + public void testConsentPersistWithoutAuthResource() { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn("1234").when(consentDataMock).getConsentId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 6, expectedExceptions = ConsentException.class) + public void testAccountConsentPersistWithoutAccountIDs() throws Exception { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(true).when(consentPersistDataMock).getApproval(); + + JSONObject payload = (JSONObject) parser + .parse(ConsentAuthorizeTestConstants.ACCOUNT_PERSIST_PAYLOAD_WITHOUT_ACCOUNT_ID); + Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); + + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 7, expectedExceptions = ConsentException.class) + public void testAccountConsentPersistWithNonStringAccountIDs() throws Exception { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(true).when(consentPersistDataMock).getApproval(); + + JSONObject payload = (JSONObject) parser + .parse(ConsentAuthorizeTestConstants.PAYLOAD_WITH_NON_STRING_ACCOUNTID); + Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); + + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 9, expectedExceptions = ConsentException.class) + public void testCOFConsentPersistWithoutCOFAccount() throws Exception { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.FUNDS_CONFIRMATIONS).when(consentResourceMock) + .getConsentType(); + Mockito.doReturn(true).when(consentPersistDataMock).getApproval(); + + JSONObject payload = (JSONObject) parser + .parse(ConsentAuthorizeTestConstants.COF_PERSIST_PAYLOAD_WITHOUT_COF_ACC); + Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); + + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 10, expectedExceptions = ConsentException.class) + public void testCOFConsentPersistWithNonStringCOFAccount() throws Exception { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.FUNDS_CONFIRMATIONS).when(consentResourceMock) + .getConsentType(); + Mockito.doReturn(true).when(consentPersistDataMock).getApproval(); + + JSONObject payload = (JSONObject) parser + .parse(ConsentAuthorizeTestConstants.COF_PERSIST_PAYLOAD_WITH_NON_STRING_COF_ACC); + Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); + + consentPersistStep.execute(consentPersistDataMock); + } + + @Test(priority = 11, expectedExceptions = ConsentException.class) + public void testCOFPersistThrowingExceptionWhenConsentBinding() throws Exception { + + Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); + Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); + Mockito.doReturn(ConsentAuthorizeTestConstants.FUNDS_CONFIRMATIONS).when(consentResourceMock) + .getConsentType(); + Mockito.doReturn(false).when(consentPersistDataMock).getApproval(); + JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + JSONObject payload = (JSONObject) parser + .parse(ConsentAuthorizeTestConstants.COF_PERSIST_PAYLOAD); + Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); + + consentPersistStep.execute(consentPersistDataMock); +} + +// @Test +// public void testAccountConsentPersistSuccessScenarioWithApprovalTrue() +// throws ParseException, ConsentManagementException { +// +// Mockito.doReturn(consentDataMock).when(consentPersistDataMock).getConsentData(); +// Mockito.doReturn(ConsentAuthorizeTestConstants.CONSENT_ID).when(consentDataMock).getConsentId(); +// Mockito.doReturn(ConsentAuthorizeTestConstants.USER_ID).when(consentDataMock).getUserId(); +// Mockito.doReturn(ConsentAuthorizeTestConstants.CLIENT_ID).when(consentDataMock).getClientId(); +// Mockito.doReturn(consentResourceMock).when(consentDataMock).getConsentResource(); +// Mockito.doReturn(ConsentAuthorizeTestConstants.getAuthResource()).when(consentDataMock).getAuthResource(); +// Mockito.doReturn(ConsentAuthorizeTestConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); +// Mockito.doReturn(true).when(consentPersistDataMock).getApproval(); +// +// Mockito.doReturn(true).when(consentCoreServiceMock).bindUserAccountsToConsent( +// Mockito.anyObject(), Mockito.anyString(), Mockito.anyString(), Mockito.anyMap(), +// Mockito.anyString(), Mockito.anyString()); +// +// PowerMockito.mockStatic(ConsentServiceUtil.class); +// PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); +// +// JSONObject payload = (JSONObject) parser.parse(ConsentAuthorizeTestConstants.ACCOUNT_PERSIST_PAYLOAD); +// Mockito.doReturn(payload).when(consentPersistDataMock).getPayload(); +// +// consentPersistStep.execute(consentPersistDataMock); +// } +} + + + + diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/ConsentExtensionDataProvider.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/ConsentExtensionDataProvider.java new file mode 100644 index 00000000..098a8706 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/ConsentExtensionDataProvider.java @@ -0,0 +1,36 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.authorize.vrp.retrieval.flow; + +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentAuthorizeTestConstants; +import org.testng.annotations.DataProvider; + +/** + * Data Provider for Consent Executor Tests. + */ +public class ConsentExtensionDataProvider { + + @DataProvider(name = "PaymentConsentDataDataProvider") + Object[][] getPaymentConsentDataDataProvider() { + + return new Object[][]{ + {ConsentAuthorizeTestConstants.PAYMENT_INITIATION}, + {ConsentAuthorizeTestConstants.INTERNATIONAL_PAYMENT_INITIATION} + }; + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalStepTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalStepTest.java new file mode 100644 index 00000000..f8b11e02 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalStepTest.java @@ -0,0 +1,282 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.authorize.vrp.retrieval.flow; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.DefaultConsentRetrievalStep; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentAuthorizeTestConstants; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.AuthorizationResource; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentFile; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.ParseException; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Test class for Consent Retrieval Step. + */ +@PrepareForTest({OpenBankingConfigParser.class, OpenBankingConfigParser.class, ConsentServiceUtil.class}) +@PowerMockIgnore({"com.wso2.openbanking.accelerator.consent.extensions.common.*", "net.minidev.*", + "jdk.internal.reflect.*"}) +public class VRPConsentRetrievalStepTest extends PowerMockTestCase { + + private static DefaultConsentRetrievalStep defaultConsentRetrievalStep; + @Mock + private static ConsentData consentDataMock; + @Mock + private static ConsentResource consentResourceMock; + @Mock + private static AuthorizationResource authorizationResourceMock; + @Mock + ConsentFile consentFileMock; + @Mock + ConsentCoreServiceImpl consentCoreServiceMock; + @Mock + OpenBankingConfigParser openBankingConfigParserMock; + + private static Map configMap; + ArrayList authResources; + + @BeforeClass + public void initClass() { + + MockitoAnnotations.initMocks(this); + + defaultConsentRetrievalStep = new DefaultConsentRetrievalStep(); + consentDataMock = Mockito.mock(ConsentData.class); + consentResourceMock = Mockito.mock(ConsentResource.class); + authorizationResourceMock = Mockito.mock(AuthorizationResource.class); + consentFileMock = Mockito.mock(ConsentFile.class); + consentCoreServiceMock = Mockito.mock(ConsentCoreServiceImpl.class); + + configMap = new HashMap<>(); + openBankingConfigParserMock = Mockito.mock(OpenBankingConfigParser.class); + authResources = new ArrayList(); + } + + @BeforeMethod + public void initMethod() throws ReflectiveOperationException { + + //to execute util class initialization + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + + OpenBankingConfigParser openBankingConfigParserMock = Mockito.mock(OpenBankingConfigParser.class); + Mockito.doReturn("jdbc/WSO2OB_DB").when(openBankingConfigParserMock).getDataSourceName(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + + Mockito.doReturn(configMap).when(openBankingConfigParserMock).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + } + + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } + + @Test + public void testGetConsentDataSetForNonRegulatory() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(false).when(consentDataMock).isRegulatory(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertTrue(jsonObject.isEmpty()); + } + + @Test + public void testConsentRetrievalWithEmptyConsentData() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + Assert.assertFalse(errorMsg.contains(ErrorConstants.REQUEST_OBJ_EXTRACT_ERROR)); + } + + @Test + public void testConsentRetrievalWithNonJWTRequestObject() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn("request=qwertyuijhbvbn").when(consentDataMock).getSpQueryParams(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + Assert.assertTrue(errorMsg.contains(ErrorConstants.REQUEST_OBJ_NOT_SIGNED)); + } + + @Test + public void testConsentRetrievalWithInvalidRequestObject() { + + String request = "request=" + ConsentAuthorizeTestConstants.INVALID_REQUEST_OBJECT; + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn(request).when(consentDataMock).getSpQueryParams(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + Assert.assertTrue(errorMsg.contains(ErrorConstants.NOT_JSON_PAYLOAD)); + } + + @Test + public void testConsentRetrievalWithValidRequestObject() throws ConsentManagementException { + + String request = "request=" + ConsentAuthorizeTestConstants.VALID_REQUEST_OBJECT; + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn(request).when(consentDataMock).getSpQueryParams(); + + Mockito.doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(consentResourceMock).getCurrentStatus(); + Mockito.doReturn(ConsentExtensionConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VALID_INITIATION_OBJECT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(consentResourceMock).when(consentCoreServiceMock) + .getConsent(Mockito.anyString(), Mockito.anyBoolean()); + Mockito.doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(authorizationResourceMock) + .getAuthorizationStatus(); + authResources.add(authorizationResourceMock); + Mockito.doReturn(authResources).when(consentCoreServiceMock) + .searchAuthorizations(Mockito.anyString()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + } + + @Test + public void testGetConsentDataSetForAccounts() { + + Mockito.doReturn(ConsentExtensionConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VALID_INITIATION_OBJECT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray accountConsentData = defaultConsentRetrievalStep.getConsentDataSet(consentResourceMock); + Assert.assertNotNull(accountConsentData); + } + + + + @Test(dataProvider = "PaymentConsentDataDataProvider", dataProviderClass = ConsentExtensionDataProvider.class) + public void testGetConsentDataSetForPayments(String paymentReceipt) throws ConsentManagementException, + ParseException { + + Mockito.doReturn(configMap).when(openBankingConfigParserMock).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + + Mockito.doReturn(ConsentExtensionConstants.PAYMENTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(paymentReceipt).when(consentResourceMock).getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CREATED_TIME).when(consentResourceMock) + .getCreatedTime(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray paymentConsentData = defaultConsentRetrievalStep.getConsentDataSet(consentResourceMock); + Assert.assertNotNull(paymentConsentData); + } + + @Test + public void testGetConsentDataSetForFilePayments() { + + Mockito.doReturn(configMap).when(openBankingConfigParserMock).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + Mockito.doReturn(ConsentExtensionConstants.PAYMENTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CREATED_TIME).when(consentResourceMock) + .getCreatedTime(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray paymentConsentData = defaultConsentRetrievalStep.getConsentDataSet(consentResourceMock); + Assert.assertNotNull(paymentConsentData); + } + + + @Test + public void testGetConsentDataSetForCOF() { + + Mockito.doReturn(ConsentExtensionConstants.FUNDSCONFIRMATIONS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.COF_RECEIPT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray cofConsentData = defaultConsentRetrievalStep.getConsentDataSet(consentResourceMock); + Assert.assertNotNull(cofConsentData); + } + + @Test + public void testGetConsentDataSetForVRP() { + + Mockito.doReturn(ConsentExtensionConstants.VRP).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VRP_INITIATION).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray cofConsentData = defaultConsentRetrievalStep.getConsentDataSet(consentResourceMock); + Assert.assertNotNull(cofConsentData); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalUtilTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalUtilTest.java new file mode 100644 index 00000000..9ad35bf6 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authorize/vrp/retrieval/flow/VRPConsentRetrievalUtilTest.java @@ -0,0 +1,333 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.authorize.vrp.retrieval.flow; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.impl.DefaultConsentRetrievalStep; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.model.ConsentData; +import com.wso2.openbanking.accelerator.consent.extensions.authorize.utils.ConsentRetrievalUtil; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentAuthorizeTestConstants; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.AuthorizationResource; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +import static com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentAuthorizeTestConstants.VRP_WITHOUT_DATA; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.when; +import static org.testng.Assert.assertTrue; + +/** + * Test class for consentRetrievalUtil. + */ +@PowerMockIgnore({"com.wso2.openbanking.accelerator.consent.extensions.common.*", "net.minidev.*", + "jdk.internal.reflect.*"}) +@PrepareForTest({OpenBankingConfigParser.class, OpenBankingConfigParser.class, ConsentServiceUtil.class}) +public class VRPConsentRetrievalUtilTest extends PowerMockTestCase { + + @InjectMocks + private final DefaultConsentRetrievalStep defaultConsentRetrievalStep = new DefaultConsentRetrievalStep(); + private final ConsentRetrievalUtil consentRetrievalUtil = new ConsentRetrievalUtil(); + @Mock + private static ConsentData consentDataMock; + @Mock + private static ConsentResource consentResourceMock; + @Mock + private static AuthorizationResource authorizationResourceMock; + @Mock + ConsentCoreServiceImpl consentCoreServiceMock; + @Mock + OpenBankingConfigParser openBankingConfigParser; + @Mock + OpenBankingConfigParser openBankingConfigParse; + private static Map configMap; + ArrayList authResources; + + + @BeforeClass + public void initClass() { + MockitoAnnotations.initMocks(this); + consentDataMock = mock(ConsentData.class); + consentResourceMock = mock(ConsentResource.class); + authorizationResourceMock = mock(AuthorizationResource.class); + consentCoreServiceMock = mock(ConsentCoreServiceImpl.class); + configMap = new HashMap<>(); + authResources = new ArrayList(); + } + + @BeforeClass + public void setUp() throws ReflectiveOperationException { + + MockitoAnnotations.initMocks(this); + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + + consentResourceMock = mock(ConsentResource.class); + + } + + @BeforeMethod + public void initMethod() { + openBankingConfigParser = mock(OpenBankingConfigParser.class); + doReturn(configMap).when(openBankingConfigParser).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); + + } + + @ObjectFactory + public IObjectFactory getObjectFactory() { + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } + + @Test + public void testGetConsentDataSetForNonRegulatory() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(false).when(consentDataMock).isRegulatory(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + assertTrue(jsonObject.isEmpty()); + } + + @Test + public void testConsentRetrievalWithEmptyConsentData() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + Assert.assertFalse(errorMsg.contains(ErrorConstants.REQUEST_OBJ_EXTRACT_ERROR)); + } + + @Test + public void testConsentRetrievalWithNonJWTRequestObject() { + + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn("request=qwertyuijhbvbn").when(consentDataMock).getSpQueryParams(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + Assert.assertTrue(errorMsg.contains(ErrorConstants.REQUEST_OBJ_NOT_SIGNED)); + } + + @Test + public void testConsentRetrievalWithInvalidRequestObject() { + + String request = "request=" + ConsentAuthorizeTestConstants.INVALID_REQUEST_OBJECT; + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn(request).when(consentDataMock).getSpQueryParams(); + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + String errorMsg = (String) jsonObject.get(ConsentExtensionConstants.IS_ERROR); + assertTrue(errorMsg.contains(ErrorConstants.NOT_JSON_PAYLOAD)); + } + + @Test + public void testConsentRetrievalWithValidRequestObject() throws ConsentManagementException { + + String request = "request=" + ConsentAuthorizeTestConstants.VALID_REQUEST_OBJECT; + JSONObject jsonObject = new JSONObject(); + Mockito.doReturn(true).when(consentDataMock).isRegulatory(); + Mockito.doReturn(request).when(consentDataMock).getSpQueryParams(); + + Mockito.doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(consentResourceMock).getCurrentStatus(); + Mockito.doReturn(ConsentExtensionConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VALID_INITIATION_OBJECT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(consentResourceMock).when(consentCoreServiceMock) + .getConsent(Mockito.anyString(), Mockito.anyBoolean()); + Mockito.doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(authorizationResourceMock) + .getAuthorizationStatus(); + authResources.add(authorizationResourceMock); + Mockito.doReturn(authResources).when(consentCoreServiceMock) + .searchAuthorizations(Mockito.anyString()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + defaultConsentRetrievalStep.execute(consentDataMock, jsonObject); + Assert.assertNotNull(jsonObject.get(ConsentExtensionConstants.IS_ERROR)); + } + + @Test + public void testGetConsentDataSetForAccounts() { + Mockito.doReturn(ConsentExtensionConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VALID_INITIATION_OBJECT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray accountConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(accountConsentData); + } + + @Test(dataProvider = "PaymentConsentDataDataProvider", dataProviderClass = ConsentExtensionDataProvider.class) + public void testGetConsentDataSetForPayments(String paymentReceipt) { + + Mockito.doReturn(configMap).when(openBankingConfigParse).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParse); + + Mockito.doReturn(ConsentExtensionConstants.PAYMENTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(paymentReceipt).when(consentResourceMock).getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.CREATED_TIME).when(consentResourceMock) + .getCreatedTime(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray paymentConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(paymentConsentData); + } + + @Test + public void testGetConsentDataSetForCOF() { + + Mockito.doReturn(ConsentExtensionConstants.FUNDSCONFIRMATIONS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.COF_RECEIPT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray cofConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(cofConsentData); + } + + @Test + public void testGetConsentDataSetForVRPData() { + + Mockito.doReturn(ConsentExtensionConstants.VRP).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VRP_INITIATION).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + JSONArray vrpConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(vrpConsentData); + } + + @Test(expectedExceptions = ConsentException.class) + public void testConsentDataWithInvalidJson() { + String invalidJsonString = "Invalid JSON String"; + Mockito.when(consentResourceMock.getReceipt()).thenReturn(invalidJsonString); + + JSONArray consentDataJSON = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(consentDataJSON); + } + + @Test(expectedExceptions = ConsentException.class) + public void testGetConsentDataSetForVRPDataParameter() { + + Mockito.doReturn(ConsentExtensionConstants.VRP).when(consentResourceMock).getConsentType(); + Mockito.doReturn(VRP_WITHOUT_DATA).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + JSONArray vrpConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(vrpConsentData); + } + + @Test(expectedExceptions = ConsentException.class) + public void testGetConsentDataSetForVRPDataWithoutControlParameters() { + + Mockito.doReturn(ConsentExtensionConstants.VRP).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.VRP_WITHOUT_CONTROLPARAMETERS).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray vrpConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(vrpConsentData); + } + + @Test(expectedExceptions = ConsentException.class) + public void testGetConsentDataSetForAccount() { + + Mockito.doReturn(ConsentExtensionConstants.ACCOUNTS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.INVALID_INITIATION_OBJECT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray accountConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(accountConsentData); + } + + @Test(expectedExceptions = ConsentException.class) + public void testGetConsentDataSetForCOFs() { + + Mockito.doReturn(ConsentExtensionConstants.FUNDSCONFIRMATIONS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.INVALID_COF_RECEIPT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray cofConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(cofConsentData); + } + + @Test(expectedExceptions = ConsentException.class) + public void testGetConsentDataSetForCOFNull() { + + Mockito.doReturn(ConsentExtensionConstants.FUNDSCONFIRMATIONS).when(consentResourceMock).getConsentType(); + Mockito.doReturn(ConsentAuthorizeTestConstants.NULL_COF_RECEIPT).when(consentResourceMock) + .getReceipt(); + Mockito.doReturn(ConsentAuthorizeTestConstants.AWAITING_AUTH_STATUS).when(consentResourceMock) + .getCurrentStatus(); + + JSONArray cofConsentData = ConsentRetrievalUtil.getConsentData(consentResourceMock); + Assert.assertNotNull(cofConsentData); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/AuthServletTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/AuthServletTest.java new file mode 100644 index 00000000..3fe0b66a --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/authservlet/impl/AuthServletTest.java @@ -0,0 +1,181 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.authservlet.impl; + +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.utils.AuthServletTestConstants; +import org.json.JSONObject; +import org.junit.Assert; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Map; +import java.util.ResourceBundle; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * Test class for OB Auth Servlet. + */ +@PowerMockIgnore("jdk.internal.reflect.*") +public class AuthServletTest { + + OBDefaultAuthServletImpl obAuthServlet; + @Mock + HttpServletRequest httpServletRequestMock; + @Mock + ResourceBundle resourceBundle; + + @BeforeClass + public void initClass() { + + MockitoAnnotations.initMocks(this); + + obAuthServlet = new OBDefaultAuthServletImpl(); + httpServletRequestMock = Mockito.mock(HttpServletRequest.class); + resourceBundle = Mockito.mock(ResourceBundle.class); + } + + @Test + public void testUpdateRequestAttributeForAccounts() { + + JSONObject accountObj = new JSONObject(AuthServletTestConstants.ACCOUNT_DATA); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + accountObj, resourceBundle); + + Assert.assertFalse(requestAttributes.isEmpty()); + Assert.assertTrue(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForCOF() { + + JSONObject cofObj = new JSONObject(AuthServletTestConstants.COF_DATA); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + cofObj, resourceBundle); + + Assert.assertFalse(requestAttributes.isEmpty()); + Assert.assertTrue(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForPayments() { + + JSONObject paymentObj = new JSONObject(AuthServletTestConstants.PAYMENT_DATA); + HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(httpServletRequestMock).getSession(); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + paymentObj, resourceBundle); + + Assert.assertFalse(requestAttributes.isEmpty()); + Assert.assertTrue(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForPaymentsWithoutDebtorAccInPayload() { + + JSONObject paymentObj = new JSONObject(AuthServletTestConstants.PAYMENT_DATA_WITHOUT_DEBTOR_ACC); + HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(httpServletRequestMock).getSession(); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + paymentObj, resourceBundle); + + Assert.assertTrue(requestAttributes.isEmpty()); + Assert.assertFalse(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForVRP() { + + JSONObject paymentObj = new JSONObject(AuthServletTestConstants.VRP_DATA); + HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(httpServletRequestMock).getSession(); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + paymentObj, resourceBundle); + + Assert.assertFalse(requestAttributes.isEmpty()); + Assert.assertTrue(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForVRPWithoutDebtorAcc() { + + JSONObject paymentObj = new JSONObject(AuthServletTestConstants.VRP_DATA_WITHOUT_DEBTOR_ACC); + HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(httpServletRequestMock).getSession(); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + paymentObj, resourceBundle); + + Assert.assertFalse(requestAttributes.isEmpty()); + Assert.assertTrue(requestAttributes.containsKey(ConsentExtensionConstants.DATA_REQUESTED)); + } + + @Test + public void testUpdateRequestAttributeForNonExistingType() { + + JSONObject object = new JSONObject(AuthServletTestConstants.JSON_WITH_TYPE); + + Map requestAttributes = obAuthServlet.updateRequestAttribute(httpServletRequestMock, + object, resourceBundle); + + Assert.assertTrue(requestAttributes.isEmpty()); + } + + @Test + public void testUpdateConsentData() { + + String param = "Test_parameter"; + Mockito.doReturn(param).when(httpServletRequestMock).getParameter(Mockito.anyString()); + HttpSession session = Mockito.mock(HttpSession.class); + Mockito.doReturn(session).when(httpServletRequestMock).getSession(); + + Map consentData = obAuthServlet.updateConsentData(httpServletRequestMock); + Assert.assertFalse(consentData.isEmpty()); + Assert.assertTrue(consentData.containsKey(ConsentExtensionConstants.ACCOUNT_IDS)); + Assert.assertFalse(consentData.containsKey(ConsentExtensionConstants.PAYMENT_ACCOUNT)); + Assert.assertFalse(consentData.containsKey(ConsentExtensionConstants.COF_ACCOUNT)); + } + + @Test + public void testUpdateConsentMetaData() { + + Map consentMetadata = obAuthServlet.updateConsentMetaData(httpServletRequestMock); + + Assert.assertTrue(consentMetadata.isEmpty()); + } + + @Test + public void testUpdateSessionAttribute() { + + Map sessionAttributes = obAuthServlet.updateSessionAttribute(httpServletRequestMock, + new JSONObject(), resourceBundle); + + Assert.assertTrue(sessionAttributes.isEmpty()); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidatorTests.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidatorTests.java new file mode 100644 index 00000000..f6afd117 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/common/idempotency/IdempotencyValidatorTests.java @@ -0,0 +1,303 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.common.idempotency; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Test class for IdempotencyValidator. + */ +@PrepareForTest({OpenBankingConfigParser.class, ConsentExtensionsDataHolder.class}) +@PowerMockIgnore("jdk.internal.reflect.*") +public class IdempotencyValidatorTests extends PowerMockTestCase { + + @Mock + private ConsentManageData consentManageData; + private ConsentCoreServiceImpl consentCoreServiceImpl; + private ArrayList consentIdList; + private Map attributeList; + private String consentId; + private Map configs; + private Map headers; + private static final String CLIENT_ID = "testClientId"; + + private static final String PAYLOAD = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"Initiation\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"165.88\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"UK.OBIE.SortCodeAccountNumber\",\n" + + " \"Identification\": \"08080021325698\",\n" + + " \"Name\": \"ACME Inc\",\n" + + " \"SecondaryIdentification\": \"0002\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"FRESCO-101\",\n" + + " \"Unstructured\": \"Internal ops code 5120101\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " }\n" + + " }\n" + + "}"; + + private static final String DIFFERENT_PAYLOAD = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"No\",\n" + + " \"Initiation\": {\n" + + " \"InstructionIdentification\": \"ACME413\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"165.88\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"UK.OBIE.SortCodeAccountNumber\",\n" + + " \"Identification\": \"08080021325698\",\n" + + " \"Name\": \"ACME Inc\",\n" + + " \"SecondaryIdentification\": \"0002\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"FRESCO-101\",\n" + + " \"Unstructured\": \"Internal ops code 5120101\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " }\n" + + " }\n" + + "}"; + + + @BeforeClass + public void beforeTest() { + configs = new HashMap<>(); + + headers = new HashMap<>(); + headers.put(IdempotencyConstants.X_IDEMPOTENCY_KEY, "123456"); + headers.put(IdempotencyConstants.CONTENT_TYPE_TAG, "application/json"); + + consentManageData = Mockito.mock(ConsentManageData.class); + consentCoreServiceImpl = Mockito.mock(ConsentCoreServiceImpl.class); + + consentId = UUID.randomUUID().toString(); + consentIdList = new ArrayList<>(); + consentIdList.add(consentId); + + attributeList = new HashMap<>(); + attributeList.put(consentId, "123456"); + } + + @BeforeMethod + public void beforeMethod() { + OpenBankingConfigParser openBankingConfigParserMock = PowerMockito.mock(OpenBankingConfigParser.class); + Mockito.doReturn(configs).when(openBankingConfigParserMock).getConfiguration(); + Mockito.doReturn(true).when(openBankingConfigParserMock).isIdempotencyValidationEnabled(); + Mockito.doReturn("1").when(openBankingConfigParserMock).getIdempotencyAllowedTime(); + ConsentExtensionsDataHolder consentExtensionsDataHolderMock = PowerMockito + .mock(ConsentExtensionsDataHolder.class); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + + PowerMockito.mockStatic(ConsentExtensionsDataHolder.class); + PowerMockito.when(ConsentExtensionsDataHolder.getInstance()).thenReturn(consentExtensionsDataHolderMock); + PowerMockito.when(consentExtensionsDataHolderMock.getConsentCoreService()).thenReturn(consentCoreServiceImpl); + } + + @Test + public void testValidateIdempotency() throws ConsentManagementException, IdempotencyValidationException { + OffsetDateTime offsetDateTime = OffsetDateTime.now(); + + Mockito.doReturn(consentIdList).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(getConsent(offsetDateTime.toEpochSecond())).when(consentCoreServiceImpl) + .getDetailedConsent(Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + IdempotencyValidationResult result = new IdempotencyValidator().validateIdempotency(consentManageData); + + Assert.assertTrue(result.isIdempotent()); + Assert.assertTrue(result.isValid()); + Assert.assertNotNull(result.getConsent()); + Assert.assertEquals(consentId, result.getConsentId()); + } + + @Test(expectedExceptions = IdempotencyValidationException.class) + public void testValidateIdempotencyForRequestsWithoutPayload() throws ConsentManagementException, + IdempotencyValidationException { + OffsetDateTime offsetDateTime = OffsetDateTime.now(); + + Mockito.doReturn(attributeList).when(consentCoreServiceImpl).getConsentAttributesByName(Mockito.anyString()); + Mockito.doReturn(getConsent(offsetDateTime.toEpochSecond())).when(consentCoreServiceImpl) + .getDetailedConsent(Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn("{}").when(consentManageData).getPayload(); + Mockito.doReturn("{}").when(consentManageData).getPayload(); + Mockito.doReturn("/payments/".concat(consentId)).when(consentManageData).getRequestPath(); + new IdempotencyValidator().validateIdempotency(consentManageData); + } + + @Test + public void testValidateIdempotencyWithoutIdempotencyKeyValue() throws IdempotencyValidationException { + + Mockito.doReturn(new HashMap<>()).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + IdempotencyValidationResult result = new IdempotencyValidator().validateIdempotency(consentManageData); + + Assert.assertFalse(result.isIdempotent()); + } + + @Test + public void testValidateIdempotencyWithoutRequest() throws IdempotencyValidationException { + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn("").when(consentManageData).getPayload(); + IdempotencyValidationResult result = new IdempotencyValidator().validateIdempotency(consentManageData); + + Assert.assertFalse(result.isIdempotent()); + } + + @Test + public void testValidateIdempotencyRetrievingAttributesWithException() + throws ConsentManagementException, IdempotencyValidationException { + + Mockito.doThrow(ConsentManagementException.class).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + IdempotencyValidationResult result = new IdempotencyValidator().validateIdempotency(consentManageData); + + Assert.assertFalse(result.isIdempotent()); + } + + @Test + public void testValidateIdempotencyWithoutAttribute() + throws ConsentManagementException, IdempotencyValidationException { + + Mockito.doReturn(new ArrayList<>()).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + IdempotencyValidationResult result = new IdempotencyValidator().validateIdempotency(consentManageData); + + Assert.assertFalse(result.isIdempotent()); + } + + @Test(expectedExceptions = IdempotencyValidationException.class) + public void testValidateIdempotencyWithNullConsentRequest() + throws ConsentManagementException, IdempotencyValidationException { + + Mockito.doReturn(consentIdList).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + Mockito.doReturn(null).when(consentCoreServiceImpl).getDetailedConsent(Mockito.anyString()); + new IdempotencyValidator().validateIdempotency(consentManageData); + } + + @Test(expectedExceptions = IdempotencyValidationException.class) + public void testValidateIdempotencyWithNonMatchingClientId() + throws ConsentManagementException, IdempotencyValidationException { + + Mockito.doReturn(consentIdList).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn("sampleClientID").when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + Mockito.doReturn(null).when(consentCoreServiceImpl).getDetailedConsent(Mockito.anyString()); + new IdempotencyValidator().validateIdempotency(consentManageData); + } + + @Test(expectedExceptions = IdempotencyValidationException.class) + public void testValidateIdempotencyAfterAllowedTime() + throws ConsentManagementException, IdempotencyValidationException { + + OffsetDateTime offsetDateTime = OffsetDateTime.now().minusHours(2); + + Mockito.doReturn(consentIdList).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(getConsent(offsetDateTime.toEpochSecond())).when(consentCoreServiceImpl) + .getDetailedConsent(Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(PAYLOAD).when(consentManageData).getPayload(); + new IdempotencyValidator().validateIdempotency(consentManageData); + } + + @Test(expectedExceptions = IdempotencyValidationException.class) + public void testValidateIdempotencyWithNonMatchingPayload() + throws ConsentManagementException, IdempotencyValidationException { + + OffsetDateTime offsetDateTime = OffsetDateTime.now(); + + Mockito.doReturn(consentIdList).when(consentCoreServiceImpl) + .getConsentIdByConsentAttributeNameAndValue(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(getConsent(offsetDateTime.toEpochSecond())).when(consentCoreServiceImpl) + .getDetailedConsent(Mockito.anyString()); + Mockito.doReturn(headers).when(consentManageData).getHeaders(); + Mockito.doReturn(CLIENT_ID).when(consentManageData).getClientId(); + Mockito.doReturn(DIFFERENT_PAYLOAD).when(consentManageData).getPayload(); + new IdempotencyValidator().validateIdempotency(consentManageData); + + } + + private DetailedConsentResource getConsent(long createdTime) { + DetailedConsentResource consent = new DetailedConsentResource(); + consent.setConsentID(consentId); + consent.setReceipt(PAYLOAD); + consent.setClientID(CLIENT_ID); + consent.setCreatedTime(createdTime); + return consent; + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentHandlerTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentHandlerTest.java new file mode 100644 index 00000000..48e8ab94 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentHandlerTest.java @@ -0,0 +1,149 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.vrp; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentException; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.internal.ConsentExtensionsDataHolder; +import com.wso2.openbanking.accelerator.consent.extensions.manage.impl.VRPConsentRequestHandler; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.when; + +/** + * Test class for VRPConsentRequestHandler. + */ +@PowerMockIgnore({"jdk.internal.reflect.*", +"com.wso2.openbanking.accelerator.consent.extensions.common.*"}) +@PrepareForTest({OpenBankingConfigParser.class, ConsentServiceUtil.class, + ConsentExtensionsDataHolder.class}) +public class VRPConsentHandlerTest extends PowerMockTestCase { + + @InjectMocks + private final VRPConsentRequestHandler handler = new VRPConsentRequestHandler(); + + @Mock + private ConsentManageData consentManageData; + + @Mock + OpenBankingConfigParser openBankingConfigParser; + + @Mock + ConsentCoreServiceImpl consentCoreServiceImpl; + + private static Map configMap; + + + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } + + @BeforeClass + public void setUp() throws ReflectiveOperationException { + MockitoAnnotations.initMocks(this); + + configMap = new HashMap<>(); + + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + + consentManageData = mock(ConsentManageData.class); + } + + @BeforeMethod + public void initMethod() { + + openBankingConfigParser = mock(OpenBankingConfigParser.class); + doReturn(configMap).when(openBankingConfigParser).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); + + } + + @Test(expectedExceptions = ConsentException.class) + public void testHandleConsentManageGetWithValidConsentIdAndMatchingClientId() throws ConsentManagementException { + UUID consentIdUUID = UUID.randomUUID(); + doReturn("vrp-consent/".concat(consentIdUUID.toString())).when(consentManageData).getRequestPath(); + ConsentResource consent = mock(ConsentResource.class); + doReturn("5678").when(consent).getClientID(); + + consentCoreServiceImpl = mock(ConsentCoreServiceImpl.class); + doReturn(consent).when(consentCoreServiceImpl).getConsent(anyString(), anyBoolean()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceImpl); + + String expectedClientId = "matchingClientId"; + doReturn(expectedClientId).when(consentManageData).getClientId(); + + handler.handleConsentManageGet(consentManageData); + } + + + @Test(expectedExceptions = ConsentException.class) + public void testHandleConsentManageDeleteWithValidConsent() throws ConsentManagementException { + + UUID consentIdUUID = UUID.randomUUID(); + doReturn("vrp-consent/".concat(consentIdUUID.toString())).when(consentManageData).getRequestPath(); + ConsentResource consent = mock(ConsentResource.class); + doReturn("5678").when(consent).getClientID(); + + consentCoreServiceImpl = mock(ConsentCoreServiceImpl.class); + doReturn(consent).when(consentCoreServiceImpl).getConsent(anyString(), anyBoolean()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceImpl); + + String expectedClientId = "6788"; + doReturn(expectedClientId).when(consentManageData).getClientId(); + + handler.handleConsentManageDelete(consentManageData); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentRequestValidatorTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentRequestValidatorTest.java new file mode 100644 index 00000000..12ec982a --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPConsentRequestValidatorTest.java @@ -0,0 +1,2009 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.vrp; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.manage.model.ConsentManageData; +import com.wso2.openbanking.accelerator.consent.extensions.manage.validator.VRPConsentRequestValidator; +import com.wso2.openbanking.accelerator.consent.extensions.util.ConsentManageUtil; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertFalse; + +/** + * Test class for VRPConsentRequestValidator. + */ +@PowerMockIgnore({"jdk.internal.reflect.*"}) +@PrepareForTest({OpenBankingConfigParser.class}) +public class VRPConsentRequestValidatorTest extends PowerMockTestCase { + + @Mock + private ConsentManageData consentManageData; + + @Mock + OpenBankingConfigParser openBankingConfigParser; + + private static Map configMap; + + @BeforeClass + public void setUp() throws ReflectiveOperationException { + MockitoAnnotations.initMocks(this); + + configMap = new HashMap<>(); + //to execute util class initialization + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + + consentManageData = mock(ConsentManageData.class); + } + + @BeforeMethod + public void initMethod() { + + openBankingConfigParser = mock(OpenBankingConfigParser.class); + Mockito.doReturn(configMap).when(openBankingConfigParser).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParser); + } + + @Test + public void testVrpPayload() { + + VRPConsentRequestValidator handler = new VRPConsentRequestValidator(); + JSONObject response = handler.validateVRPPayload("payload"); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, response.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testVrpEmptyPayload() { + + JSONObject response = VRPConsentRequestValidator.validateVRPPayload(""); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, response.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiation() { + + String initiationPayloads = VRPTestConstants.vrpInitiationPayloadWithoutData; + JSONObject response = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, response.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpControlParameters() { + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CONTROL_PARAMETERS; + JSONObject response = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testVrpEmptyData() { + String initiationPayloads = VRPTestConstants.vrpInitiationPayloadWithStringData; + JSONObject response = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, response.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpDataIsJsonObject() { + String initiationPayloads = VRPTestConstants.vrpInitiationPayloadWithOutJsonObject; + JSONObject response = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, response.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutControlParameterKey() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CONTROL_PARAMETERS; + JSONObject result = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result2 = VRPConsentRequestValidator.validateMaximumIndividualAmount((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result3 = VRPConsentRequestValidator. + validateMaximumIndividualAmountCurrency((JSONObject) JSONValue.parse(initiationPayloads)); + + Assert.assertTrue(true); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyWithCurrencyKeys() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("Currency", "USD"); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + Assert.assertTrue((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testValidateAmountCurrencyWithInvalidKey() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("InvalidKey", "USD"); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutPeriodicLimitCurrency() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_PERIODIC_LIMIT_CURRENCY; + JSONObject results = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result = VRPConsentRequestValidator.validateCurrencyPeriodicLimit((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) results.get(ConsentExtensionConstants.IS_VALID)); + assertTrue(true); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testVrpInitiationPayloadWithoutPeriodicLimitAmount() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_PERIODIC_LIMIT_AMOUNT; + JSONObject results = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) results.get(ConsentExtensionConstants.IS_VALID)); + assertTrue(true); + + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithInvalidValue() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("Currency", 123); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithInvalidKey() { + + JSONArray testData = new JSONArray(); + JSONObject limit = new JSONObject(); + limit.put("anotherKey", "USD"); + testData.add(limit); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData, "currency", String.class); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidationFailureForCurrency() { + + JSONObject limit = new JSONObject(); + limit.put(ConsentExtensionConstants.CURRENCY, 123); + + JSONArray periodicLimits = new JSONArray(); + periodicLimits.add(limit); + + JSONObject result = VRPConsentRequestValidator.validateAmountCurrencyPeriodicLimits(periodicLimits, + ConsentExtensionConstants.CURRENCY, String.class); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("The value of 'Currency' is not of type String", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithCurrencyKey() { + + // Test case 2: Invalid currency key (empty value) + JSONArray testData2 = new JSONArray(); + JSONObject limit2 = new JSONObject(); + limit2.put("currency", ""); + testData2.add(limit2); + + JSONObject result2 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData2, "0", String.class); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + JSONArray testData3 = new JSONArray(); + + JSONObject result3 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData3, "0", String.class); + Assert.assertTrue((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + + JSONObject result4 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(null, "currency", String.class); + Assert.assertFalse((boolean) result4.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result4.get(ConsentExtensionConstants.ERRORS)); + + + } + + @Test + public void testVrpInitiationPayloadWithoutRisk() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_RISK; + JSONObject result = VRPConsentRequestValidator.validateConsentRisk((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testIsValidObjectDebAcc() { + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + // Test case 3: Non-JSONObject value + String nonJsonObject = "not a JSONObject"; + Assert.assertFalse(VRPConsentRequestValidator.isValidJSONObject(nonJsonObject), + ConsentExtensionConstants.IS_VALID); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + + // Test case 4: Null value + Object nullValue = null; + Assert.assertFalse(VRPConsentRequestValidator.isValidJSONObject(nullValue), + ConsentExtensionConstants.IS_VALID); + + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testIsValidObjectDebtorAcc() { + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + // Test case 3: Non-JSONObject value + String nonJsonObject = "not a JSONObject"; + Assert.assertFalse(VRPConsentRequestValidator.isValidJSONObject(nonJsonObject), + ConsentExtensionConstants.IS_VALID); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + // Test case 4: Null value + Object nullValue = null; + Assert.assertFalse(VRPConsentRequestValidator.isValidJSONObject(nullValue), + ConsentExtensionConstants.IS_VALID); + } + + @Test + public void testVrpInitiationPayloadWithoutDebtorAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutCreditAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_CREDITOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutCreditorAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_CREDITOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutSchemeName() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT_SCHEME_NAME; + JSONObject result = ConsentManageUtil.validateDebtorAccount((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_DEBTOR_ACC_SCHEME_NAME, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateDebtorAccount_InvalidSchemeName() { + JSONObject debtorAccount = new JSONObject(); + debtorAccount.put(ConsentExtensionConstants.SCHEME_NAME, ""); + debtorAccount.put(ConsentExtensionConstants.IDENTIFICATION, "ValidIdentification"); + debtorAccount.put(ConsentExtensionConstants.NAME, "ValidName"); + + JSONObject result = ConsentManageUtil.validateDebtorAccount(debtorAccount); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(result.get(ConsentExtensionConstants.ERRORS), + ErrorConstants.MISSING_DEBTOR_ACC_SCHEME_NAME); + } + + @Test + public void testVrpInitiationPayloadWithoutIdentification() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT_IDENTIFICATION; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testVrpInitiationPayloadCreditorAccWithoutSchemeName() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_CREDITOR_ACCOUNT_SCHEME_NAME; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload((JSONValue. + parse(initiationPayloads))); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + + } + + @Test + public void testVrpInitiationPayloadCreditorAccWithoutIdentification() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_CREDITOR_ACCOUNT_IDENTIFICATION; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + + } + + @Test + public void testValidatePeriodicLimits() { + + JSONObject invalidLimit = new JSONObject(); + invalidLimit.put("someKey", "someValue"); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(invalidLimit); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_LIMITS, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithValidKey() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("Currency", "USD"); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + Assert.assertTrue(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithInvalidKeys() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("InvalidKey", "USD"); + + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithEmptyArray() { + + JSONArray jsonArray = new JSONArray(); + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(jsonArray, "Currency", String.class); + + Assert.assertTrue(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(null, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimitsWithNullArray() { + + JSONObject result = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(null, "Currency", String.class); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("parameter passed in is null", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testVrpPeriodicTypeJsonArray() { + + Object invalidObject = "Not a JSONArray"; + boolean isValidInvalidObject = VRPConsentRequestValidator.isValidJSONArray(invalidObject); + + // Test case 2: Missing period type key + JSONObject missingKeyObject = new JSONObject(); + JSONObject result2 = VRPConsentRequestValidator.validatePeriodType(missingKeyObject); + Assert.assertFalse(Boolean.parseBoolean(result2.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 3: Null period type + JSONObject nullPeriodTypeObject = new JSONObject(); + nullPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, null); + JSONObject result3 = VRPConsentRequestValidator.validatePeriodType(nullPeriodTypeObject); + Assert.assertFalse(Boolean.parseBoolean(result3.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 4: Empty period type + JSONObject emptyPeriodTypeObject = new JSONObject(); + emptyPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, ""); + JSONObject result4 = VRPConsentRequestValidator.validatePeriodType(emptyPeriodTypeObject); + Assert.assertFalse(Boolean.parseBoolean(result4.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 5: Invalid period type + JSONObject invalidPeriodTypeObject = new JSONObject(); + invalidPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, "InvalidType"); + JSONObject result5 = VRPConsentRequestValidator.validatePeriodType(invalidPeriodTypeObject); + Assert.assertFalse(Boolean.parseBoolean(result5.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, result2.get(ConsentExtensionConstants.ERRORS)); + + Assert.assertFalse(isValidInvalidObject, ConsentExtensionConstants.IS_VALID); + } + + @Test + public void testDataContainsKey_InitiationNotPresent() { + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_INITIATION; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + + boolean containsKey = result.containsKey(ConsentExtensionConstants.INITIATION); + Assert.assertFalse(containsKey, ConsentExtensionConstants.IS_VALID); + Assert.assertEquals("Missing mandatory parameter Initiation in the payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testDataContainsKey_ControlParametersNotPresent() { + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CONTROL_PARAMETERS; + JSONObject result = VRPConsentRequestValidator.validateConsentControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean containsKey = result.containsKey(ConsentExtensionConstants.CONTROL_PARAMETERS); + Assert.assertFalse(containsKey, ConsentExtensionConstants.IS_VALID); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_CONTROL_PARAMETER, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadMaximumIndividualAmountNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_EMPTY_MAX_INDIVIDUAL_AMOUNT; + String date = VRPTestConstants.METADATA_VRP_WITHOUT_VALID_FROM_DATE; + String date2 = VRPTestConstants.METADATA_VRP_WITHOUT_VALID_TO_DATE; + + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmount((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject results = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result2 = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(date)); + JSONObject result3 = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(date)); + + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + + + boolean isValidNonJSONObjects = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObjects, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) results.get(ConsentExtensionConstants.IS_VALID)); + + boolean obj2 = VRPConsentRequestValidator.isValidJSONObject(date); + Assert.assertFalse(obj2, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + + boolean obj3 = VRPConsentRequestValidator.isValidJSONObject(date2); + Assert.assertFalse(obj3, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testVrpInitiationPayloadDebAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_DEBTOR_ACC; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadDebAccs() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_DEB_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Parameter 'debtor account' passed in is null, empty, or not a JSONObject", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationMax() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_EMPTY_MAX_INDIVIDUAL_AMOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR, result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadValidateDebAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_DEB_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadCreditorAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CREDITOR_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadCreditorAccs() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CREDITOR_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Parameter 'creditor account' passed in is null, empty, or not a JSONObject", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadDebtorAccs() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_DEB_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + + Assert.assertEquals("Parameter 'debtor account' passed in is null, empty, or not a JSONObject", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testIsValidObject_NegativeScenarios() { + + String nonJSONObject = "Not a JSONObject"; + JSONObject validInitiationObject = new JSONObject(); + + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(nonJSONObject); + boolean isValidNonJSONObject1 = VRPConsentRequestValidator.isValidJSONObject(validInitiationObject); + Assert.assertFalse(isValidNonJSONObject1, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testVrpInitiationPayloadInitiationNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_EMPTY_INITIATION; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Parameter 'initiation' passed in is null, empty, or not a JSONObject", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadMaximumIndividualNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_INVALID_MAX_INDIVIDUAL_AMOUNT; + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmount((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadCurrencyNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_INVALID_MAX_INDIVIDUAL_AMOUNT; + JSONObject result = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadControlParametersNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_EMPTY_CONTROL_PARAMETERS; + JSONObject result = VRPConsentRequestValidator.validateConsentControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Parameter 'control parameters' passed in is null, empty, or not a JSONObject", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutDate() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_INVALID_VALID_FROM_DATETIME; + JSONObject result = VRPConsentRequestValidator.validateParameterDateTime((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_VALID_TO_DATE_TIME, + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testVrpInitiationPayloadWithoutValidToDate() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_VALID_TO_DATE; + JSONObject result = VRPConsentRequestValidator.validateParameterDateTime((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_VALID_TO_DATE_TIME, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadMaximumIndividualAmountIsJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_EMPTY_MAX_INDIVIDUAL_AMOUNT; + JSONObject result = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testIsValidDateTimeObjectNegativeScenarios() { + // Test case 1: Empty string + String emptyString = ""; + JSONObject resultEmptyString = VRPConsentRequestValidator.isValidDateTimeObject(emptyString); + Assert.assertFalse((boolean) resultEmptyString.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_DATE_TIME_FORMAT, + resultEmptyString.get(ConsentExtensionConstants.ERRORS)); + + // Test case 2: Null value + Object nullValue = null; + boolean resultNullValue = false; + Assert.assertFalse(resultNullValue, "Expected false for a null value"); + + // Test case 3: Non-string value + Object nonStringValue = 123; // Assuming an integer, but could be any non-string type + JSONObject resultNonStringValue = VRPConsentRequestValidator.isValidDateTimeObject(nonStringValue); + Assert.assertFalse((boolean) resultNonStringValue.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_DATE_TIME_FORMAT, + resultNonStringValue.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimits() { + + // Test case 2: Key is null + JSONArray testData2 = new JSONArray(); + JSONObject result2 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData2, null, String.class); + Assert.assertTrue((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 3: ParentObj is null + JSONObject result3 = VRPConsentRequestValidator.validateAmountCurrencyPeriodicLimits(null, "0", String.class); + Assert.assertTrue((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 4: Key is not present in parentObj + JSONArray testData4 = new JSONArray(); + JSONObject result4 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData4, "nonExistentKey", String.class); + Assert.assertTrue((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 5: Value is an empty String + JSONArray testData5 = new JSONArray(); + testData5.add(""); + JSONObject result5 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData5, "0", String.class); + Assert.assertTrue((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result2.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidateKeyAndNonEmptyStringValue() { + + // Test case 2: Key is null + JSONArray testData2 = new JSONArray(); + JSONObject result2 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData2, null, String.class); + Assert.assertTrue((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 3: ParentObj is null + JSONObject result3 = VRPConsentRequestValidator.validateAmountCurrencyPeriodicLimits(null, "0", String.class); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result3.get(ConsentExtensionConstants.ERRORS)); + + // Test case 4: Key is not present in parentObj + JSONArray testData4 = new JSONArray(); + JSONObject result4 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData4, "nonExistentKey", String.class); + Assert.assertTrue((boolean) result4.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result4.get(ConsentExtensionConstants.ERRORS)); + + // Test case 5: Value is an empty String + JSONArray testData5 = new JSONArray(); + testData5.add(""); + JSONObject result5 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData5, "0", String.class); + Assert.assertTrue((boolean) result5.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result5.get(ConsentExtensionConstants.ERRORS)); + + + // Test case 7: Value is not a String + JSONArray testData7 = new JSONArray(); + testData7.add(123); // Assuming the value should be a String, but it's an integer in this case + JSONObject result7 = VRPConsentRequestValidator. + validateAmountCurrencyPeriodicLimits(testData7, "0", String.class); + Assert.assertTrue((boolean) result7.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(null, + result7.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidPeriodicLimitsFormat() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, "invalid-format"); + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(controlParameters); + + Assert.assertFalse((boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.INVALID_PARAMETER_PERIODIC_LIMITS, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidMaxAmountFormat() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, "invalid-format"); + JSONObject validationResult = VRPConsentRequestValidator.validateMaximumIndividualAmount(controlParameters); + + Assert.assertFalse((boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Parameter 'maximum individual amount' passed in is null, empty, or not a JSONObject", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidMaxAmountFormatPeriodicLimit() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, "invalid-format"); + JSONObject validationResults = VRPConsentRequestValidator. + validateControlParameters(controlParameters); + JSONObject validationResult = VRPConsentRequestValidator. + validateMaximumIndividualAmountCurrency(controlParameters); + + Assert.assertFalse((boolean) validationResults.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidMaxAmountFormats() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, "invalid-format"); + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(controlParameters); + + Assert.assertFalse((boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.INVALID_PARAMETER_PERIODIC_LIMITS, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidJSONObject() { + + String invalidJSONObject = "not a JSON object"; + boolean isValid = VRPConsentRequestValidator.isValidJSONObject(invalidJSONObject); + + Assert.assertFalse(isValid); + } + + @Test + public void testEmptyJSONObject() { + JSONObject emptyJSONObject = new JSONObject(); + + boolean isValid = VRPConsentRequestValidator.isValidJSONObject(emptyJSONObject); + Assert.assertFalse(isValid); + } + + @Test + public void testInvalidPeriodicAlignment() { + // Arrange + JSONObject invalidLimit = new JSONObject(); + invalidLimit.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "InvalidAlignment"); + + JSONObject isValid = VRPConsentRequestValidator.validatePeriodicLimits(invalidLimit); + + Assert.assertFalse((boolean) isValid.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_LIMITS, + isValid.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidDateTimeRange() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.VALID_FROM_DATE_TIME, "2023-01-01T00:00:00Z"); + controlParameters.put(ConsentExtensionConstants.VALID_TO_DATE_TIME, "2022-01-01T00:00:00Z"); + + boolean hasValidFromDate = controlParameters.containsKey(ConsentExtensionConstants.VALID_FROM_DATE_TIME); + boolean hasValidToDate = controlParameters.containsKey(ConsentExtensionConstants.VALID_TO_DATE_TIME); + + + assertTrue(hasValidFromDate && hasValidToDate); + } + + @Test + public void testVrpInitiationPayloadWithoutControlParameterss() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CURRENCY; + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmount((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Missing mandatory parameter Maximum Individual Amount", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutPeriodicType() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_PERIODIC_TYPE; + JSONObject result = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result2 = VRPConsentRequestValidator.validatePeriodicLimits((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result3 = VRPConsentRequestValidator.validatePeriodType((JSONObject) JSONValue. + parse(initiationPayloads)); + + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidationFailureForNullCurrencyKey() { + + JSONArray periodicLimits = new JSONArray(); + periodicLimits.add(new JSONObject()); + + JSONObject result = VRPConsentRequestValidator.validateAmountCurrencyPeriodicLimits(periodicLimits, + ConsentExtensionConstants.CURRENCY, String.class); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutPeriodicTypeCurrency() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_PERIODIC_TYPE_CURRENCY; + JSONObject result = VRPConsentRequestValidator.validateControlParameters((JSONObject) JSONValue. + parse(initiationPayloads)); + JSONObject result2 = VRPConsentRequestValidator.validatePeriodicLimits((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidationFailureForMissingKey() { + + JSONArray periodicLimits = new JSONArray(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("otherKey", "someValue"); + periodicLimits.add(jsonObject); + + + JSONObject result = VRPConsentRequestValidator.validateAmountCurrencyPeriodicLimits(periodicLimits, + ConsentExtensionConstants.CURRENCY, String.class); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidateControlParameters() { + + JSONObject controlParameters = new JSONObject(); + + JSONObject result = VRPConsentRequestValidator.validateControlParameters(controlParameters); + + assertTrue(result.containsKey(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testValidateAmountCurrencyPeriodicLimits_Invalid() { + + JSONObject controlParameters = new JSONObject(); + JSONArray periodicLimits = new JSONArray(); + + JSONObject invalidPeriodicLimit = new JSONObject(); + periodicLimits.add(invalidPeriodicLimit); + + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimits); + + JSONObject result = VRPConsentRequestValidator.validateCurrencyPeriodicLimit(controlParameters); + + assertTrue(result.containsKey(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimit_WithErrors() { + + JSONObject controlParameters = new JSONObject(); + JSONArray periodicLimits = new JSONArray(); + + JSONObject invalidPeriodicLimit = new JSONObject(); + periodicLimits.add(invalidPeriodicLimit); + + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimits); + + JSONObject periodicLimitType = VRPConsentRequestValidator. + validateCurrencyPeriodicLimit(controlParameters); + + Assert.assertFalse((boolean) periodicLimitType.get(ConsentExtensionConstants.IS_VALID)); + + assertTrue(periodicLimitType.containsKey(ConsentExtensionConstants.ERRORS)); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + periodicLimitType.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testValidateConsentRisk_ValidRequest() { + + JSONObject validRequest = new JSONObject(); + JSONObject data = new JSONObject(); + data.put("someKey", "someValue"); + + validRequest.put(ConsentExtensionConstants.DATA, data); + validRequest.put(ConsentExtensionConstants.RISK, new JSONObject()); + + JSONObject validationResponse = VRPConsentRequestValidator.validateConsentRisk(validRequest); + + assertTrue((boolean) validationResponse.get(ConsentExtensionConstants.IS_VALID)); + } + + @Test + public void testValidateConsentControlParameters_InvalidControlParameters() { + + JSONObject invalidControlParametersObject = new JSONObject(); + invalidControlParametersObject.put("invalidParam", "value"); + + JSONObject invalidDataObject = new JSONObject(); + invalidDataObject.put(ConsentExtensionConstants.CONTROL_PARAMETERS, invalidControlParametersObject); + + + JSONObject invalidRequestObject = new JSONObject(); + invalidRequestObject.put(ConsentExtensionConstants.DATA, invalidDataObject); + + JSONObject validationResult = VRPConsentRequestValidator.validateConsentControlParameters(invalidRequestObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_MAXIMUM_INDIVIDUAL_AMOUNT, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicLimits_Valid() { + + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimit1.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "ALIGNMENT1"); + periodicLimit1.put(ConsentExtensionConstants.PERIOD_TYPE, "TYPE1"); + + JSONObject periodicLimit2 = new JSONObject(); + periodicLimit2.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "ALIGNMENT2"); + periodicLimit2.put(ConsentExtensionConstants.PERIOD_TYPE, "TYPE2"); + + periodicLimitsArray.add(periodicLimit1); + periodicLimitsArray.add(periodicLimit2); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(controlParametersObject); + JSONObject validationResults = VRPConsentRequestValidator.validatePeriodAlignment(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertFalse(Boolean.parseBoolean(validationResults.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_ALIGNMENT, + validationResults.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicLimits_InvalidFormat() { + JSONObject controlParametersObject = new JSONObject(); + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, "InvalidFormat"); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.INVALID_PARAMETER_PERIODIC_LIMITS, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicLimits_MissingPeriodLimits() { + + JSONObject controlParametersObject = new JSONObject(); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodicLimits(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_LIMITS, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimit_Valid() { + + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimit1.put(ConsentExtensionConstants.CURRENCY, "USD"); + + JSONObject periodicLimit2 = new JSONObject(); + periodicLimit2.put(ConsentExtensionConstants.CURRENCY, "EUR"); + + periodicLimitsArray.add(periodicLimit1); + periodicLimitsArray.add(periodicLimit2); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator. + validateAmountPeriodicLimit(controlParametersObject); + + assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Amount' is not present in payload", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimit_MissingCurrency() { + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimitsArray.add(periodicLimit1); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator. + validateAmountPeriodicLimit(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Amount' is not present in payload", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicType_Valid() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_TYPE, ConsentExtensionConstants.MONTH); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + + Assert.assertTrue(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + } + + @Test + public void testValidatePeriodicType_InvalidType() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_TYPE, "InvalidType"); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.INVALID_PERIOD_TYPE, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicType_MissingType() { + + JSONObject periodicLimitObject = new JSONObject(); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicType_EmptyType() { + + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_TYPE, ""); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Value of period type is empty or the value passed in is not a string", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicType_NullType() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_TYPE, null); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Value of period type is empty or the value passed in is not a string", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testYourMethod_ValidPeriodicType() { + + JSONObject controlParameters = new JSONObject(); + JSONArray periodicLimits = new JSONArray(); + + JSONObject periodicLimit = new JSONObject(); + periodicLimit.put(ConsentExtensionConstants.PERIOD_TYPE, ConsentExtensionConstants.MONTH); + periodicLimits.add(periodicLimit); + + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimits); + + JSONObject result = VRPConsentRequestValidator.validateAmountPeriodicLimit(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Amount' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testYourMethod_InvalidPeriodicType() { + + JSONObject controlParameters = new JSONObject(); + JSONArray periodicLimits = new JSONArray(); + + JSONObject periodicLimit = new JSONObject(); + periodicLimit.put(ConsentExtensionConstants.PERIOD_TYPE, "InvalidType"); + periodicLimits.add(periodicLimit); + + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimits); + + JSONObject result = VRPConsentRequestValidator.validateCurrencyPeriodicLimit(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testYourMethod_MissingPeriodicType() { + + JSONObject controlParameters = new JSONObject(); + + JSONObject result = VRPConsentRequestValidator.validatePeriodicLimits(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_LIMITS, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutDebtorAccs() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRisk_InvalidRequest() { + JSONObject requestBody = new JSONObject(); + JSONObject data = new JSONObject(); + data.put("key1", "value1"); + requestBody.put("data", data); + + JSONObject validationResult = VRPConsentRequestValidator.validateVRPPayload(requestBody); + JSONObject validationResults = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertFalse(Boolean.parseBoolean(validationResults.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + validationResults.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutDeAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadDAccWithoutSchemeName() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT_SCHEME_NAME; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload((JSONValue. + parse(initiationPayloads))); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_DEBTOR_ACC_SCHEME_NAME, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadDAccWithoutIdentification() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT_IDENTIFICATION; + JSONObject result = VRPConsentRequestValidator.validateVRPPayload(JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_DEBTOR_ACC_IDENTIFICATION, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadDAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_DEBTOR_ACC; + JSONObject result = VRPConsentRequestValidator.validateVRPInitiationPayload((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutDAcc() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_DEBTOR_ACCOUNT; + JSONObject result = VRPConsentRequestValidator.validateConsentInitiation((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_DEBTOR_ACC, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateMaximumIndividualAmountCurrency_InvalidAmountCurrency() { + JSONObject controlParameters = new JSONObject(); + JSONObject maximumIndividualAmount = new JSONObject(); + maximumIndividualAmount.put("InvalidKey", "USD"); + controlParameters.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, maximumIndividualAmount); + + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateMaximumIndividualAmountCurrency_MissingCurrency() { + + JSONObject controlParameters = new JSONObject(); + JSONObject maximumIndividualAmount = new JSONObject(); + + controlParameters.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, maximumIndividualAmount); + + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodAlignmentInvalidValue() { + + JSONObject limit = new JSONObject(); + limit.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "InvalidValue"); + + JSONObject result = VRPConsentRequestValidator.validatePeriodAlignment(limit); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(result.get(ConsentExtensionConstants.ERRORS), + ErrorConstants.INVALID_PERIOD_ALIGNMENT); + } + + @Test + public void testValidatePeriodAlignmentMissingKey() { + + JSONObject limit = new JSONObject(); + + JSONObject result = VRPConsentRequestValidator.validatePeriodAlignment(limit); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(result.get(ConsentExtensionConstants.ERRORS), + ErrorConstants.MISSING_PERIOD_ALIGNMENT); + } + + + @Test + public void testValidatePeriodicAlignment_EmptyType() { + + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, ""); + + JSONObject result = VRPConsentRequestValidator.validatePeriodType(periodicLimitObject); + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_TYPE, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicAlignment() { + // Test case 1: Valid periodic type + JSONObject validLimitObject = new JSONObject(); + validLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, ConsentExtensionConstants.DAY); + JSONObject result1 = VRPConsentRequestValidator.validatePeriodAlignment(validLimitObject); + Assert.assertFalse((boolean) result1.get(ConsentExtensionConstants.IS_VALID)); + + // Test case 2: Missing period type key + JSONObject missingKeyObject = new JSONObject(); + JSONObject result2 = VRPConsentRequestValidator.validatePeriodAlignment(missingKeyObject); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + + // Test case 3: Null period type + JSONObject nullPeriodTypeObject = new JSONObject(); + nullPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, null); + JSONObject result3 = VRPConsentRequestValidator.validatePeriodAlignment(nullPeriodTypeObject); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + + // Test case 4: Empty period type + JSONObject emptyPeriodTypeObject = new JSONObject(); + emptyPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, ""); + JSONObject result4 = VRPConsentRequestValidator.validatePeriodAlignment(emptyPeriodTypeObject); + Assert.assertFalse((boolean) result4.get(ConsentExtensionConstants.IS_VALID)); + + // Test case 5: Invalid period type + JSONObject invalidPeriodTypeObject = new JSONObject(); + invalidPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "InvalidType"); + JSONObject result5 = VRPConsentRequestValidator.validatePeriodAlignment(invalidPeriodTypeObject); + Assert.assertFalse((boolean) result5.get(ConsentExtensionConstants.IS_VALID)); + + Assert.assertEquals("Invalid value for period alignment in PeriodicLimits", + result5.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicAlignment_Valid() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, ConsentExtensionConstants.CONSENT); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodAlignment(periodicLimitObject); + + Assert.assertTrue(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + + } + + @Test + public void testValidatePeriodicAlignment_InvalidType() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "InvalidType"); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodAlignment(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Invalid value for period alignment in PeriodicLimits", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicAlignment_MissingType() { + + JSONObject periodicLimitObject = new JSONObject(); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodAlignment(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.MISSING_PERIOD_ALIGNMENT, + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicAlignments_EmptyType() { + + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, ""); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodAlignment(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Value of periodic alignment is empty or the value passed in is not a string", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicAlignment_NullType() { + JSONObject periodicLimitObject = new JSONObject(); + periodicLimitObject.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, null); + + JSONObject validationResult = VRPConsentRequestValidator.validatePeriodAlignment(periodicLimitObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Value of periodic alignment is empty or the value passed in is not a string", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimits_Valid() { + + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimit1.put(ConsentExtensionConstants.CURRENCY, "USD"); + + JSONObject periodicLimit2 = new JSONObject(); + periodicLimit2.put(ConsentExtensionConstants.CURRENCY, "EUR"); + + periodicLimitsArray.add(periodicLimit1); + periodicLimitsArray.add(periodicLimit2); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator. + validateCurrencyPeriodicLimit(controlParametersObject); + + + } + + + @Test + public void testValidateAmountCurrencyPeriodicLimitS_MissingCurrency() { + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimitsArray.add(periodicLimit1); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator. + validateCurrencyPeriodicLimit(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + validationResult.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testYourMethod_ValidPeriodicTypes() { + + JSONObject controlParameters = new JSONObject(); + JSONArray periodicLimits = new JSONArray(); + + JSONObject periodicLimit = new JSONObject(); + periodicLimit.put(ConsentExtensionConstants.PERIOD_TYPE, ConsentExtensionConstants.MONTH); + periodicLimits.add(periodicLimit); + + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimits); + + JSONObject result = VRPConsentRequestValidator.validateCurrencyPeriodicLimit(controlParameters); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + } + + @Test + public void testValidateAmountCurrencyPeriodicLimits_MissingCurrency() { + JSONObject controlParametersObject = new JSONObject(); + JSONArray periodicLimitsArray = new JSONArray(); + + JSONObject periodicLimit1 = new JSONObject(); + periodicLimitsArray.add(periodicLimit1); + + controlParametersObject.put(ConsentExtensionConstants.PERIODIC_LIMITS, periodicLimitsArray); + + JSONObject validationResult = VRPConsentRequestValidator. + validateCurrencyPeriodicLimit(controlParametersObject); + + Assert.assertFalse(Boolean.parseBoolean(validationResult.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("Mandatory parameter 'Currency' is not present in payload", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadMaximumIndividualAmountCurrencyNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_EMPTY_MAX_INDIVIDUAL_AMOUNT; + + JSONObject results = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + + boolean isValidNonJSONObjects = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObjects, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) results.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + results.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadMaximumIndividualCurrencyNotJsonObject() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITH_INVALID_MAX_INDIVIDUAL_AMOUNT; + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + boolean isValidNonJSONObject = VRPConsentRequestValidator.isValidJSONObject(initiationPayloads); + Assert.assertFalse(isValidNonJSONObject, (ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testInvalidMaxAmountCurrencyFormatPeriodicLimit() { + + JSONObject controlParameters = new JSONObject(); + controlParameters.put(ConsentExtensionConstants.PERIODIC_LIMITS, "invalid-format"); + JSONObject validationResults = VRPConsentRequestValidator. + validateControlParameters(controlParameters); + JSONObject validationResult = VRPConsentRequestValidator. + validateMaximumIndividualAmountCurrency(controlParameters); + + Assert.assertFalse((boolean) validationResults.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertFalse((boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testInvalidCurrencyKey_MissingKeys() { + + JSONObject maximumIndividualAmount = new JSONObject(); + + JSONObject validationResults = VRPConsentRequestValidator. + validateJsonObjectKey(maximumIndividualAmount, ConsentExtensionConstants.CURRENCY, String.class); + + Assert.assertFalse((Boolean) validationResults.get(ConsentExtensionConstants.IS_VALID)); + + JSONObject parentObj = new JSONObject(); + JSONObject validationResult = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency(parentObj); + + Assert.assertFalse((Boolean) validationResult.get(ConsentExtensionConstants.IS_VALID)); + JSONObject isValid = VRPConsentRequestValidator.validateJsonObjectKey(parentObj, "Currency", String.class); + + Assert.assertFalse((Boolean) isValid.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + validationResult.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutControlParameterCurrency() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CURRENCY; + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testVrpInitiationPayloadWithoutControlParameter() { + + String initiationPayloads = VRPTestConstants.METADATA_VRP_WITHOUT_CURRENCY; + JSONObject result = VRPConsentRequestValidator.validateMaximumIndividualAmountCurrency((JSONObject) JSONValue. + parse(initiationPayloads)); + + Assert.assertFalse((boolean) result.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result.get(ConsentExtensionConstants.ERRORS)); + } + + + @Test + public void testWithEmptyDate() { + + String initiationPayloads = VRPTestConstants.vrpInitiationPayloadWithoutDate; + JSONObject response = VRPConsentRequestValidator.validateParameterDateTime((JSONObject) JSONValue. + parse(initiationPayloads)); + Assert.assertFalse((boolean) response.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals(ErrorConstants.MISSING_VALID_TO_DATE_TIME, response.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRisk() { + + JSONObject requestBody = new JSONObject(); + JSONObject data = new JSONObject(); + JSONObject risk = new JSONObject(); + + data.put(ConsentExtensionConstants.RISK, risk); + requestBody.put(ConsentExtensionConstants.DATA, data); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRiskInvalidFormat() { + JSONObject requestBody = new JSONObject(); + requestBody.put("invalidKey", "invalidValue"); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRiskMissingRiskKey() { + + JSONObject requestBody = new JSONObject(); + JSONObject data = new JSONObject(); + requestBody.put(ConsentExtensionConstants.DATA, data); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRiskWithDataEmpty() { + + JSONObject requestBody = new JSONObject(); + requestBody.put(ConsentExtensionConstants.DATA, new JSONObject()); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRiskWithDataNotPresent() { + + JSONObject requestBody = new JSONObject(); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateConsentRiskWithDataNotEmpty() { + JSONObject requestBody = new JSONObject(); + JSONObject data = new JSONObject(); + data.put("someKey", "someValue"); + requestBody.put(ConsentExtensionConstants.DATA, data); + + JSONObject result = VRPConsentRequestValidator.validateConsentRisk(requestBody); + Assert.assertFalse(Boolean.parseBoolean(result.getAsString(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals(ErrorConstants.PAYLOAD_FORMAT_ERROR_RISK, + result.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateCurrencyWithoutAmountKeyAndEmptyString() { + + // Test case 1: parentObj is null + JSONObject result1 = VRPConsentRequestValidator. + validateJsonObjectKey(null, "Currency", String.class); + Assert.assertFalse((boolean) result1.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result1.get(ConsentExtensionConstants.ERRORS)); + + // Test case 2: Key is not present in parentObj + JSONObject result2 = VRPConsentRequestValidator. + validateJsonObjectKey(new JSONObject(), "nonExistentKey", String.class); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'nonExistentKey' is not present in payload", + result2.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyWithCurrencyKey() { + + // Test case 3: Invalid currency key (missing key) + JSONObject testData3 = new JSONObject(); + + JSONObject result3 = VRPConsentRequestValidator. + validateJsonObjectKey(testData3, "currency", String.class); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'currency' is not present in payload", + result3.get(ConsentExtensionConstants.ERRORS)); + + // Test case 4: Invalid currency key (null parentObj) + JSONObject result4 = VRPConsentRequestValidator. + validateJsonObjectKey(null, "currency", String.class); + Assert.assertFalse((boolean) result4.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'currency' is not present in payload", + result3.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidatePeriodicType() { + // Test case 1: Valid periodic type + JSONObject validLimitObject = new JSONObject(); + validLimitObject.put(ConsentExtensionConstants.PERIOD_TYPE, ConsentExtensionConstants.DAY); + JSONObject result1 = VRPConsentRequestValidator.validatePeriodType(validLimitObject); + Assert.assertTrue((boolean) result1.get(ConsentExtensionConstants.IS_VALID)); + + + // Test case 2: Missing period type key + JSONObject missingKeyObject = new JSONObject(); + JSONObject result2 = VRPConsentRequestValidator.validatePeriodType(missingKeyObject); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Missing required parameter Period type", + result2.get(ConsentExtensionConstants.ERRORS)); + + // Test case 3: Null period type + JSONObject nullPeriodTypeObject = new JSONObject(); + nullPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, null); + JSONObject result3 = VRPConsentRequestValidator.validatePeriodType(nullPeriodTypeObject); + Assert.assertFalse((boolean) result3.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Missing required parameter Period type", + result2.get(ConsentExtensionConstants.ERRORS)); + + + // Test case 4: Empty period type + JSONObject emptyPeriodTypeObject = new JSONObject(); + emptyPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, ""); + JSONObject result4 = VRPConsentRequestValidator.validatePeriodType(emptyPeriodTypeObject); + Assert.assertFalse((boolean) result4.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Missing required parameter Period type", + result2.get(ConsentExtensionConstants.ERRORS)); + + + // Test case 5: Invalid period type + JSONObject invalidPeriodTypeObject = new JSONObject(); + invalidPeriodTypeObject.put(ConsentExtensionConstants.PERIOD_TYPE, "InvalidType"); + JSONObject result5 = VRPConsentRequestValidator.validatePeriodType(invalidPeriodTypeObject); + Assert.assertFalse((boolean) result5.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Missing required parameter Period type", + result2.get(ConsentExtensionConstants.ERRORS)); + } + + @Test + public void testValidateAmountCurrencyWithoutCurrentKeyAndEmptyString() { + // Test case 1: parentObj is null + JSONObject result1 = VRPConsentRequestValidator. + validateJsonObjectKey(null, "Currency", String.class); + Assert.assertFalse(((boolean) result1.get(ConsentExtensionConstants.IS_VALID))); + Assert.assertEquals("parameter passed in is null", + result1.get(ConsentExtensionConstants.ERRORS)); + + // Test case 2: Key is not present in parentObj + JSONObject result2 = VRPConsentRequestValidator. + validateJsonObjectKey(new JSONObject(), "nonExistentKey", String.class); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'nonExistentKey' is not present in payload", + result2.get(ConsentExtensionConstants.ERRORS)); + + } + + @Test + public void testValidateAmountCurrencyWithoutAmountKeyAndEmptyString() { + + // Test case 1: parentObj is null + JSONObject result1 = VRPConsentRequestValidator. + validateJsonObjectKey(null, "Amount", String.class); + Assert.assertFalse((boolean) result1.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("parameter passed in is null", + result1.get(ConsentExtensionConstants.ERRORS)); + + // Test case 2: Key is not present in parentObj + JSONObject result2 = VRPConsentRequestValidator. + validateJsonObjectKey(new JSONObject(), "nonExistentKey", String.class); + Assert.assertFalse((boolean) result2.get(ConsentExtensionConstants.IS_VALID)); + Assert.assertEquals("Mandatory parameter 'nonExistentKey' is not present in payload", + result2.get(ConsentExtensionConstants.ERRORS)); + } +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPTestConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPTestConstants.java new file mode 100644 index 00000000..f8c8535e --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/manage/vrp/VRPTestConstants.java @@ -0,0 +1,1122 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.manage.vrp; + +/** + * Constant class for consent manage tests. + */ +public class VRPTestConstants { + + public static String vrpInitiationPayloadWithoutData = "{\n" + + " \"\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static String vrpInitiationPayloadWithoutDate = "{\n" + + " \"\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"\",\n" + + " \"ValidToDateTime\": null, // Set to null instead of an empty string\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static String vrpInitiationPayloadWithStringData = "{\n" + + " \"\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static String vrpInitiationPayloadWithOutJsonObject = "{\n" + + " \"\": { }" + + ",\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_CREDITOR_ACCOUNT = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_DEBTOR_ACCOUNT = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + ; + + + public static final String METADATA_VRP_DEBTOR_ACCOUNT_SCHEME_NAME = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_CREDITOR_ACCOUNT_SCHEME_NAME = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_DEBTOR_ACCOUNT_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_CREDITOR_ACCOUNT_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_INITIATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_CONTROL_PARAMETERS = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_CURRENCY = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITHOUT_PERIODIC_LIMIT_CURRENCY = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITHOUT_PERIODIC_LIMIT_AMOUNT = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_PERIODIC_TYPE = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_PERIODIC_TYPE_CURRENCY = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"\": \"\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodicType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITHOUT_VALID_TO_DATE = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITH_INVALID_VALID_FROM_DATETIME = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"\": \"2023-09-12T\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITH_INVALID_MAX_INDIVIDUAL_AMOUNT = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": \"\",\n" + // Empty string for MaximumIndividualAmount + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_RISK = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITH_EMPTY_CONTROL_PARAMETERS = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": \"\",\n" + // Empty string for ControlParameters + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_EMPTY_INITIATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": \"\",\n" + // Empty string for Initiation + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITH_EMPTY_MAX_INDIVIDUAL_AMOUNT = "{\n" + + " \"\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": \"\",\n" + // Empty string for MaximumIndividualAmount + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITHOUT_VALID_FROM_DATE = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String METADATA_VRP_WITHOUT_DEB_ACC = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": \"\",\n" + // Change DebtorAccount to an empty string + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_DEBTOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"\": \"\",\n" + // Change DebtorAccount to an empty string + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + + public static final String METADATA_VRP_WITHOUT_CREDITOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": \"\", // Change CreditorAccount to an empty string\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + } diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/AuthServletTestConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/AuthServletTestConstants.java new file mode 100644 index 00000000..a2d462af --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/AuthServletTestConstants.java @@ -0,0 +1,256 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +/** + * Constant class for OB Auth Servlet tests. + */ +public class AuthServletTestConstants { + public static final String ACCOUNT_DATA = "{" + + " \"consentData\": [" + + " {" + + " \"data\":[" + + " \"ReadAccountsBasic\"," + + " \"ReadAccountsDetail\"," + + " \"ReadBalances\"," + + " ]," + + " \"title\":\"Permissions\"" + + " }," + + " {" + + " \"data\":[\"2021-07-19T13:51:43.347+05:30\"]," + + " \"title\":\"Expiration Date Time\"" + + " }," + + " {" + + " \"data\":[\"2021-07-14T13:51:43.397+05:30\"]," + + " \"title\":\"Transaction From Date Time\"" + + " }," + + " {" + + " \"data\":[\"2021-07-17T13:51:43.397+05:30\"]," + + " \"title\":\"Transaction To Date Time\"}," + + " ]," + + " \"application\":\"9b5usDpbNtmxDcTzs7GzKp\"," + + " \"accounts\":[" + + " {" + + " \"accountId\":\"30080012343456\"," + + " \"account_id\":\"30080012343456\"," + + " \"authorizationMethod\":\"single\"," + + " \"accountName\":\"account_1\"," + + " \"nickName\":\"not-working\"," + + " \"display_name\":\"account_1\"" + + " }," + + " {" + + " \"accountId\":\"30080098763459\"," + + " \"account_id\":\"30080098763459\"," + + " \"authorizationMethod\":\"single\"," + + " \"accountName\":\"account_2\"," + + " \"display_name\":\"account_2\"" + + " }" + + " ]," + + " \"type\":\"accounts\"" + + "}"; + + public static final String COF_DATA = "{" + + " \"consentData\":[" + + " {" + + " \"data\":[\"2021-07-19T20:14:11.069+05:30\"]," + + " \"title\":\"Expiration Date Time\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 1234\"," + + " \"Name : Account1\"," + + " \"Secondary Identification : Account1\"" + + " ]," + + " \"title\":\"Debtor Account\"" + + " }," + + " ]," + + " \"application\":\"9b5usDpbNtmxDcTzs7GzKp\"," + + " \"type\":\"fundsconfirmations\"," + + " \"debtor_account\":\"1234\"" + + "}"; + + public static final String PAYMENT_DATA = "{" + + " \"consentData\":[" + + " {" + + " \"data\":[\"Domestic Payments\"]," + + " \"title\":\"Payment Type\"" + + " }," + + " {" + + " \"data\":[\"ACME412\"]," + + " \"title\":\"Instruction Identification\"" + + " }," + + " {" + + " \"data\":[\"FRESCO.21302.GFX.20\"]," + + " \"title\":\"End to End Identification\"" + + " }," + + " {" + + " \"data\":[\"Amount : 30.80\",\"Currency : GBP\"]," + + " \"title\":\"Instructed Amount\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 30080012343456\"," + + " \"Name : Andrea Smith\"," + + " \"Secondary Identification : 30080012343456\"" + + " ]," + + " \"title\":\"Debtor Account\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 08080021325698\"," + + " \"Name : ACME Inc\"," + + " \"Secondary Identification : 0002\"" + + " ]," + + " \"title\":\"Creditor Account\"" + + " }," + + " ]," + + " \"application\":\"9b5usDpbNtmxDcTzs7GzKp\"," + + " \"type\":\"payments\"," + + " \"debtor_account\":\"30080012343456\"" + + "}"; + + public static final String PAYMENT_DATA_WITHOUT_DEBTOR_ACC = "{\n" + + " \"consentData\":[\n" + + " {\n" + + " \"data\":[\n" + + " \"Domestic Payments\"\n" + + " ],\n" + + " \"title\":\"Payment Type\"\n" + + " },\n" + + " {\n" + + " \"data\":[\n" + + " \"ACME412\"\n" + + " ],\n" + + " \"title\":\"Instruction Identification\"\n" + + " },\n" + + " {\n" + + " \"data\":[\n" + + " \"FRESCO.21302.GFX.20\"\n" + + " ],\n" + + " \"title\":\"End to End Identification\"\n" + + " },\n" + + " {\n" + + " \"data\":[\n" + + " \"Amount : 30.80\",\n" + + " \"Currency : GBP\"\n" + + " ],\n" + + " \"title\":\"Instructed Amount\"\n" + + " },\n" + + " {\n" + + " \"data\":[\n" + + " \"Scheme Name : OB.SortCodeAccountNumber\",\n" + + " \"Identification : 08080021325698\",\n" + + " \"Name : ACME Inc\"\n" + + " ],\n" + + " \"title\":\"Creditor Account\"\n" + + " },\n" + + " ]," + + " \"type\":\"Payments\"\n" + + "}"; + + + public static final String VRP_DATA = "{" + + " \"consentData\":[" + + " {" + + " \"data\":[\"Domestic VRP\"]," + + " \"title\":\"Payment Type\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 30080012343456\"," + + " \"Name : Andrea Smith\"," + + " \"Secondary Identification : 30080012343456\"" + + " ]," + + " \"title\":\"Debtor Account\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 08080021325698\"," + + " \"Name : ACME Inc\"," + + " \"Secondary Identification : 0002\"" + + " ]," + + " \"title\":\"Creditor Account\"" + + " }," + + " {" + + " \"data\":[\"100\"]," + + " \"title\":\"Maximum amount per payment\"" + + " }," + + " {" + + " \"data\":[\"Consent\"]," + + " \"title\":\"Period Alignment\"" + + " }," + + " {" + + " \"data\":[\"200\"]," + + " \"title\":\"Maximum payment amount per Week\"" + + " }," + + " ]," + + " \"application\":\"9b5usDpbNtmxDcTzs7GzKp\"," + + " \"type\":\"vrp\"," + + " \"debtor_account\":\"30080012343456\"" + + "}"; + + + public static final String VRP_DATA_WITHOUT_DEBTOR_ACC = "{" + + " \"consentData\":[" + + " {" + + " \"data\":[\"Domestic VRP\"]," + + " \"title\":\"Payment Type\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 30080012343456\"," + + " \"Name : Andrea Smith\"," + + " \"Secondary Identification : 30080012343456\"" + + " ]," + + " \"title\":\"Debtor Account\"" + + " }," + + " {" + + " \"data\":[" + + " \"Scheme Name : OB.SortCodeAccountNumber\"," + + " \"Identification : 08080021325698\"," + + " \"Name : ACME Inc\"," + + " \"Secondary Identification : 0002\"" + + " ]," + + " \"title\":\"Creditor Account\"" + + " }," + + " {" + + " \"data\":[\"100\"]," + + " \"title\":\"Maximum amount per payment\"" + + " }," + + " {" + + " \"data\":[\"Consent\"]," + + " \"title\":\"Period Alignment\"" + + " }," + + " {" + + " \"data\":[\"200\"]," + + " \"title\":\"Maximum payment amount per Week\"" + + " }," + + " ]," + + " \"type\":\"vrp\"," + + "}"; + + public static final String JSON_WITH_TYPE = "{" + + " \"type\":\"test\"" + + "}"; +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentAuthorizeTestConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentAuthorizeTestConstants.java new file mode 100644 index 00000000..71bac8ce --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentAuthorizeTestConstants.java @@ -0,0 +1,405 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.AuthorizationResource; + +import java.time.Instant; +import java.time.OffsetDateTime; + +/** + * Constant class for consent authorize tests. + */ +public class ConsentAuthorizeTestConstants { + public static final String INVALID_REQUEST_OBJECT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aWF0.TIygRaBn7MUFR9Zzy3" + + "yu9K8uKVe8KXdAty0Ckrg2vFI"; + public static final String VALID_REQUEST_OBJECT = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkR3TUtkV01tajdQV2" + + "ludm9xZlF5WFZ6eVo2USJ9.eyJtYXhfYWdlIjo4NjQwMCwiYXVkIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6OTQ0Ni9vYXV0aDIvdG9rZW4iL" + + "CJzY29wZSI6Im9wZW5pZCBhY2NvdW50cyIsImlzcyI6InF3ZGZnaGpwbG1nZmRhYWhrZ2pvcGhuayIsImNsYWltcyI6eyJpZF90b2tlb" + + "iI6eyJhY3IiOnsidmFsdWVzIjpbInVybjpvcGVuYmFua2luZzpwc2QyOnNjYSIsInVybjpvcGVuYmFua2luZzpwc2QyOmNhIl0sImVzc" + + "2VudGlhbCI6dHJ1ZX0sIm9wZW5iYW5raW5nX2ludGVudF9pZCI6eyJ2YWx1ZSI6IjEyMzQ1Njc3NjU0MzIxMjM0MjM0IiwiZXNzZW50a" + + "WFsIjp0cnVlfX0sInVzZXJpbmZvIjp7Im9wZW5iYW5raW5nX2ludGVudF9pZCI6eyJ2YWx1ZSI6IjEyMzQ1Njc3NjU0MzIxMjM0MjM0I" + + "iwiZXNzZW50aWFsIjp0cnVlfX19LCJyZXNwb25zZV90eXBlIjoiY29kZSBpZF90b2tlbiIsInJlZGlyZWN0X3VyaSI6Imh0dHBzOi8vd" + + "3NvMi5jb20iLCJzdGF0ZSI6IllXbHpjRG96TVRRMiIsImV4cCI6MTY1MzcxNzQ3OCwibm9uY2UiOiJuLTBTNl9XekEyTSIsImNsaWVud" + + "F9pZCI6InF3ZGZnaGpwbG1nZmRhYWhrZ2pvcGhuayJ9.lOvcc81dqjqdv4dslB_Kg4K3TKd13UQWaUKl3dBiPPlnu9y-R84Xfx-bMMnH" + + "atYyW9hYWJcUlprIm_dqgFXauCSTgBz6-vacrXLzuaGtj07d-8bL_qta45qbpbKPTY2pnM_PXe7fzs4RMCGEoiRLRs7lJUBfIbV9GzlS" + + "pHkOZiOjiFxxeYm0cNpZRvXkZNd59_GLdW2kKmWaGQHpQ9Ci_QpQENRzF8KEV1QtNd3cK2DjL5tKSw824C6AmXp-PKfvhurqPaVkz5p-" + + "iPA6bRaNBPY4hj_nsZpfuCnE8-V7YXWXXzWbK3gWo_dMOV1CZcHS6KqP7DANqDEEP4LoN081uQ"; + + public static final OffsetDateTime EXP_DATE = OffsetDateTime.now().plusDays(50); + + public static final OffsetDateTime INVALID_EXP_DATE = OffsetDateTime.now().plusDays(0); + + public static final OffsetDateTime NULL_EXP_DATE = null; + public static final String VALID_INITIATION_OBJECT = "{\"Data\": {\"Permissions\": [\"ReadAccountsDetail\"," + + "\"ReadBalances\",\"ReadBeneficiariesDetail\",\"ReadDirectDebits\",\"ReadProducts\"," + + "\"ReadStandingOrdersDetail\",\"ReadTransactionsCredits\",\"ReadTransactionsDebits\"," + + "\"ReadTransactionsDetail\",\"ReadOffers\",\"ReadPAN\",\"ReadParty\",\"ReadPartyPSU\"," + + " \"ReadScheduledPaymentsDetail\",\"ReadStatementsDetail\"],\"ExpirationDateTime\": " + + "\"" + EXP_DATE + "\",\"TransactionFromDateTime\": \"2021-05-03T00:00:00+00:00\"," + + "\"TransactionToDateTime\": \"2021-12-03T00:00:00+00:00\"},\"Risk\": {}}"; + + public static final String INVALID_INITIATION_OBJECT = "{\"Data\": {\"Permissions\": [\"ReadAccountsDetail\"," + + "\"ReadBalances\",\"ReadBeneficiariesDetail\",\"ReadDirectDebits\",\"ReadProducts\"," + + "\"ReadStandingOrdersDetail\",\"ReadTransactionsCredits\",\"ReadTransactionsDebits\"," + + "\"ReadTransactionsDetail\",\"ReadOffers\",\"ReadPAN\",\"ReadParty\",\"ReadPartyPSU\"," + + " \"ReadScheduledPaymentsDetail\",\"ReadStatementsDetail\"],\"ExpirationDateTime\": " + + "\"" + INVALID_EXP_DATE + "\",\"TransactionFromDateTime\": \"2021-05-03T00:00:00+00:00\"," + + "\"TransactionToDateTime\": \"2021-12-03T00:00:00+00:00\"},\"Risk\": {}}"; + + + public static final String AWAITING_AUTH_STATUS = "awaitingAuthorisation"; + public static final long CREATED_TIME = Instant.now().toEpochMilli(); + public static final String ACCOUNTS = "accounts"; + public static final String PAYMENTS = "payments"; + public static final String FUNDS_CONFIRMATIONS = "fundsconfirmations"; + public static final String VRP = "vrp"; + public static final String PAYLOAD_WITH_NON_STRING_ACCOUNTID = "{\"accountIds\": [1234, 2345]}"; + public static final String CONSENT_ID = "4ae1e012-eaa7-4994-a055-c6454f0aeeb4"; + public static final String USER_ID = "admin@wso2.com"; + public static final String CLIENT_ID = "9vblw2uUr7FOfQzI0_XGzM7IRxAa"; + public static final String COF_RECEIPT = "{" + + " \"Data\": {" + + " \"DebtorAccount\": {" + + " \"SchemeName\": \"OB.IBAN\"," + + " \"Identification\": \"GB76LOYD30949301273801\"," + + " \"Name\": \"Andrea Smith\"," + + " \"SecondaryIdentification\": \"Roll 56988\"" + + " }," + + " \"ExpirationDateTime\": \"" + EXP_DATE + "\"" + + " }" + + "}"; + + public static final String INVALID_COF_RECEIPT = "{" + + " \"Data\": {" + + " \"DebtorAccount\": {" + + " \"SchemeName\": \"OB.IBAN\"," + + " \"Identification\": \"GB76LOYD30949301273801\"," + + " \"Name\": \"Andrea Smith\"," + + " \"SecondaryIdentification\": \"Roll 56988\"" + + " }," + + " \"ExpirationDateTime\": \"" + INVALID_EXP_DATE + "\"" + + " }" + + "}"; + + public static final String NULL_COF_RECEIPT = "{" + + " \"Data\": {" + + " \"DebtorAccount\": {" + + " \"SchemeName\": \"OB.IBAN\"," + + " \"Identification\": \"GB76LOYD30949301273801\"," + + " \"Name\": \"Andrea Smith\"," + + " \"SecondaryIdentification\": \"Roll 56988\"" + + " }," + + " \"ExpirationDateTime\": \"" + NULL_EXP_DATE + "\"" + + " }" + + "}"; + public static final String VRP_INITIATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2017-06-05T15:15:13+00:00\",\n" + + " \"ValidToDateTime\": \"2022-07-05T15:15:13+00:00\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"100.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"200.00\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Week\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"CreditorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_WITHOUT_CONTROLPARAMETERS = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"\": {\n" + + " \"ValidFromDateTime\": \"2017-06-05T15:15:13+00:00\",\n" + + " \"ValidToDateTime\": \"2022-07-05T15:15:13+00:00\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"100.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"200.00\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Week\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"CreditorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_WITHOUT_DATA = "{\n" + + " \"\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2017-06-05T15:15:13+00:00\",\n" + + " \"ValidToDateTime\": \"2022-07-05T15:15:13+00:00\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"100.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"200.00\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Week\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"CreditorAccount\": {" + + " \"Name\": \"Andrea Smith\", " + + " \"SchemeName\": \"OB.SortCodeAccountNumber\", " + + " \"Identification\": \"30080012343456\", " + + " \"SecondaryIdentification\": \"30080012343456\"" + + " }," + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + static OffsetDateTime expirationInstant = OffsetDateTime.now().plusDays(50); + public static final String PAYMENT_INITIATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"Authorisation\": {\n" + + " \"AuthorisationType\": \"Any\",\n" + + " \"CompletionDateTime\": \"" + expirationInstant + "\"\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"165\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"DebtorAccount\": {\n" + + "\"SchemeName\": \"OB.SortCodeAccountNumber\",\n" + + "\"Identification\": \"30080012343456\",\n" + + "\"Name\": \"Andrea Smith\",\n" + + "\"SecondaryIdentification\": \"30080012343456\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.SortCodeAccountNumber\",\n" + + " \"Identification\": \"08080021325698\",\n" + + " \"Name\": \"ACME Inc\",\n" + + " \"SecondaryIdentification\": \"0002\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"FRESCO-101\",\n" + + " \"Unstructured\": \"Internal ops code 5120101\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"EcommerceGoods\",\n" + + " \"MerchantCategoryCode\": \"5967\",\n" + + " \"MerchantCustomerIdentification\": \"053598653254\",\n" + + " \"DeliveryAddress\": {\n" + + " \"AddressLine\": [\n" + + " \"Flat 7\",\n" + + " \"Acacia Lodge\"\n" + + " ],\n" + + " \"StreetName\": \"Acacia Avenue\",\n" + + " \"BuildingNumber\": \"27\",\n" + + " \"PostCode\": \"GU31 2ZZ\",\n" + + " \"TownName\": \"Sparsholt\",\n" + + " \"CountySubDivision\": [\n" + + " \"Wessex\"\n" + + " ],\n" + + " \"Country\": \"UK\"\n" + + " }\n" + + " }\n" + + "}"; + public static final String INTERNATIONAL_PAYMENT_INITIATION = "" + + "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"Yes\",\n" + + " \"Initiation\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"InstructionPriority\": \"Normal\",\n" + + " \"CurrencyOfTransfer\": \"USD\",\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"165.88\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.SortCodeAccountNumber\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Andrea Smith\",\n" + + " \"SecondaryIdentification\": \"30080012343456\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.SortCodeAccountNumber\",\n" + + " \"Identification\": \"08080021325698\",\n" + + " \"Name\": \"ACME Inc\",\n" + + " \"SecondaryIdentification\": \"0002\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"FRESCO-101\",\n" + + " \"Unstructured\": \"Internal ops code 5120101\"\n" + + " },\n" + + " \"ExchangeRateInformation\": {\n" + + " \"UnitCurrency\": \"GBP\",\n" + + " \"RateType\": \"Actual\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"TransferToThirdParty\"\n" + + " }\n" + + "}"; + + public static final String ACCOUNT_PERSIST_PAYLOAD_WITHOUT_ACCOUNT_ID = " " + + "{" + + " \"metadata\": {" + + " \"commonAuthId\":\"b37b9c9b-b5ce-4889-966e-9cb30f70cc78\"" + + " }," + + " \"cofAccount\":\"\"," + + " \"approval\":\"true\"," + + " \"accountIds\": \"\"," + + " \"isReauthorization\":\"false\"," + + " \"type\":\"accounts\"," + + " \"paymentAccount\":\"\"" + + "}"; + + public static final String COF_PERSIST_PAYLOAD = " " + + "{" + + " \"metadata\": {" + + " \"commonAuthId\":\"b37b9c9b-b5ce-4889-966e-9cb30f70cc78\"" + + " }," + + " \"approval\":\"true\"," + + " \"cofAccount\":\"1234\"," + + " \"accountIds\": \"\"," + + " \"type\":\"accounts\"," + + "}"; + + public static final String COF_PERSIST_PAYLOAD_WITHOUT_COF_ACC = " " + + "{" + + " \"metadata\": {" + + " \"commonAuthId\":\"b37b9c9b-b5ce-4889-966e-9cb30f70cc78\"" + + " }," + + " \"approval\":\"true\"," + + " \"accountIds\": \"\"," + + " \"isReauthorization\":\"false\"," + + " \"type\":\"accounts\"," + + " \"paymentAccount\":\"\"" + + "}"; + + public static final String COF_PERSIST_PAYLOAD_WITH_NON_STRING_COF_ACC = " " + + "{" + + " \"metadata\": {" + + " \"commonAuthId\":\"b37b9c9b-b5ce-4889-966e-9cb30f70cc78\"" + + " }," + + " \"cofAccount\":1234," + + " \"approval\":\"true\"," + + " \"accountIds\": \"\"," + + " \"isReauthorization\":\"false\"," + + " \"type\":\"accounts\"," + + " \"paymentAccount\":\"\"" + + "}"; + + public static AuthorizationResource getAuthResource() { + + AuthorizationResource authorizationResource = new AuthorizationResource(); + authorizationResource.setAuthorizationID("1234"); + authorizationResource.setConsentID(ConsentAuthorizeTestConstants.CONSENT_ID); + authorizationResource.setAuthorizationStatus("created"); + authorizationResource.setAuthorizationType("authorization"); + + return authorizationResource; + } + + public static final String ACCOUNT_PERSIST_PAYLOAD = " " + + "{" + + " \"metadata\": {" + + " \"commonAuthId\":\"b37b9c9b-b5ce-4889-966e-9cb30f70cc78\"" + + " }," + + " \"cofAccount\":\"\"," + + " \"approval\":\"true\"," + + " \"accountIds\":[" + + " \"30080012343456\"" + + " ]," + + " \"type\":\"accounts\"," + + " \"paymentAccount\":\"\"" + + "}"; + +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionDataProvider.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionDataProvider.java new file mode 100644 index 00000000..19ea53c5 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionDataProvider.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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +import org.testng.annotations.DataProvider; + +/** + * Data Provider for Consent Executor Tests. + */ +public class ConsentExtensionDataProvider { + + @DataProvider(name = "VRPInvalidSubmissionPayloadsDataProvider") + Object[][] getVRPInvalidSubmissionPayloadsDataProvider() { + + return new Object[][]{ + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_INSTRUCTION_IDENTIFICATION}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_END_TO_IDENTIFICATION}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_INSTRUCTED_AMOUNT}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_INSTRUCTION_CREDITOR_ACC}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_INSTRUCTION_REMITTANCE_INFO}, + }; + } + + @DataProvider(name = "VRPInvalidInitiationSubmissionPayloadsDataProvider") + Object[][] getVRPInvalidInitiationSubmissionPayloadsDataProvider() { + + return new Object[][]{ + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_CREDITOR_ACC}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO}, + {ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_DEBTOR_ACC}, + }; + } + +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestConstants.java new file mode 100644 index 00000000..d7ccaa71 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestConstants.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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +/** +comment. + */ +public class ConsentExtensionTestConstants { + + public static final String VALID_INITIATION_OBJECT = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestUtils.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestUtils.java new file mode 100644 index 00000000..b945da8d --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentExtensionTestUtils.java @@ -0,0 +1,98 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.ConsentAttributes; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; + +import java.lang.reflect.Field; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; + + +/** + * Utils class for consent executor tests. + */ +public class ConsentExtensionTestUtils { + + static JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + + public static void injectEnvironmentVariable(String key, String value) + throws ReflectiveOperationException { + + Class processEnvironment = Class.forName("java.lang.ProcessEnvironment"); + + Field unmodifiableMapField = getAccessibleField(processEnvironment, "theUnmodifiableEnvironment"); + Object unmodifiableMap = unmodifiableMapField.get(null); + injectIntoUnmodifiableMap(key, value, unmodifiableMap); + + Field mapField = getAccessibleField(processEnvironment, "theEnvironment"); + Map map = (Map) mapField.get(null); + map.put(key, value); + } + + private static Field getAccessibleField(Class clazz, String fieldName) + throws NoSuchFieldException { + + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } + + private static void injectIntoUnmodifiableMap(String key, String value, Object map) + throws ReflectiveOperationException { + + Class unmodifiableMap = Class.forName("java.util.Collections$UnmodifiableMap"); + Field field = getAccessibleField(unmodifiableMap, "m"); + Object obj = field.get(map); + ((Map) obj).put(key, value); + } + + public static JSONObject getInitiationPayload(JSONObject payload) { + return (JSONObject) ((JSONObject) payload.get(ConsentExtensionConstants.DATA)) + .get(ConsentExtensionConstants.INITIATION); + } + + public static JSONObject getJsonPayload(String payload) throws ParseException { + return (JSONObject) parser.parse(payload); + } + + public static ConsentAttributes getConsentAttributes(String paymentType) { + + Map consentAttributesMap = new HashMap(); + consentAttributesMap.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, "100.00"); + consentAttributesMap.put(ConsentExtensionConstants.PAYMENT_TYPE, paymentType); + consentAttributesMap.put(ConsentExtensionConstants.PAID_AMOUNT, "20.00"); + consentAttributesMap.put(ConsentExtensionConstants.LAST_PAYMENT_DATE, + OffsetDateTime.now().minusDays(50).toString()); + consentAttributesMap.put(ConsentExtensionConstants.PREVIOUS_PAID_AMOUNT, "20.00"); + consentAttributesMap.put(ConsentExtensionConstants.PREVIOUS_LAST_PAYMENT_DATE, + OffsetDateTime.now().minusDays(50).toString()); + + ConsentAttributes consentAttributes = new ConsentAttributes(); + consentAttributes.setConsentAttributes(consentAttributesMap); + + return consentAttributes; + } + +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentValidateTestConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentValidateTestConstants.java new file mode 100644 index 00000000..0411286d --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/utils/ConsentValidateTestConstants.java @@ -0,0 +1,1091 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.utils; + +import java.time.OffsetDateTime; + +/** + * comment. + */ +public class ConsentValidateTestConstants { + public static final OffsetDateTime EXPIRATION_DATE = OffsetDateTime.now().plusDays(50); + public static final String CONSENT_ID = "0ba972a9-08cd-4cad-b7e2-20655bcbd9e0"; + public static final String INVALID_CONSENT_ID = "0ba972a9-08cd-4cad-b7e2-20655bcbd9e0"; + public static final String INVALID_CONSENT_TYPE = "InvalidConsentType"; + public static final String VRP_PATH = "/domestic-vrps"; + public static final String PAYMENT_PATH = "/domestic-payments"; + public static final String USER_ID = "admin@wso2.com"; + public static final String CLIENT_ID = "xzX8t9fx6VxYMx_B6Lgpd5_yyUEa"; + public static final String SAMPLE_AUTHORIZATION_TYPE = "authorizationType"; + public static final String VRP_INITIATION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_INITIATION_WITHOUT_DEBTOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_INITIATION_WITHOUT_CREDITOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + public static final String VRP_SUBMISSION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_RISK = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_INVALID_INSTRUCTION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"UK.OBIE.IBAN\",\n" + + " \"Identification\": \"GB76LOYD30949301273801\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"SortCodeAccountNumber\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_INVALID_RISK = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"CreditToThirdParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + " \"PSUInteractionType\": \"OffSession\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"GB76LOYD30949301273801\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"SortCodeAccountNumber\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_CREDITOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTION_REMITTANCE_INFO = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_DEBTOR_ACC_MISMATCH = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO_MISMATCH = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"ThirdParty\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTED_AMOUNT = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTION_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_END_TO_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_DEBTOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_INTEGER_INSTRUCTION_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": 788,\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_INTEGER_END_TO_IDENTIFICATION = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": 5666,\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTION_REMITTANCE_INFO_MISMATCH = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"ThirdParty\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_DEBTOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITH_INSTRUCTION_CREDITOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_SUBMISSION_WITHOUT_INSTRUCTION_CREDITOR_ACC = "{\n" + + " \"Data\": {\n" + + " \"ConsentId\": \"" + CONSENT_ID + "\",\n" + + " \"PSUAuthenticationMethod\": \"OB.SCA\",\n" + + "\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " },\n" + + "\n" + + " \"Instruction\": {\n" + + " \"InstructionIdentification\": \"ACME412\",\n" + + " \"EndToEndIdentification\": \"FRESCO.21302.GFX.20\",\n" + + " \"\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"InstructedAmount\": {\n" + + " \"Amount\": \"10.00\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + "\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; + + public static final String VRP_INSTRUCTION = "{\n" + + " \"Data\": {\n" + + " \"ReadRefundAccount\": \"true\",\n" + + " \"ControlParameters\": {\n" + + " \"ValidFromDateTime\": \"2023-09-12T12:43:07.956Z\",\n" + + " \"ValidToDateTime\": \"2024-05-12T12:43:07.956Z\",\n" + + " \"MaximumIndividualAmount\": {\n" + + " \"Amount\": \"9\",\n" + + " \"Currency\": \"GBP\"\n" + + " },\n" + + " \"PeriodicLimits\": [\n" + + " {\n" + + " \"Amount\": \"1000\",\n" + + " \"Currency\": \"GBP\",\n" + + " \"PeriodAlignment\": \"Consent\",\n" + + " \"PeriodType\": \"Half-year\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"Initiation\": {\n" + + " \"DebtorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30080012343456\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"CreditorAccount\": {\n" + + " \"SchemeName\": \"OB.IBAN\",\n" + + " \"Identification\": \"30949330000010\",\n" + + " \"SecondaryIdentification\": \"Roll 90210\",\n" + + " \"Name\": \"Marcus Sweepimus\"\n" + + " },\n" + + " \"RemittanceInformation\": {\n" + + " \"Reference\": \"Sweepco\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"Risk\": {\n" + + " \"PaymentContextCode\": \"PartyToParty\"\n" + + " }\n" + + "}"; +} diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/validate/VRPSubmissionTest.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/validate/VRPSubmissionTest.java new file mode 100644 index 00000000..70c17895 --- /dev/null +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/java/com/wso2/openbanking/accelerator/consent/extensions/validate/VRPSubmissionTest.java @@ -0,0 +1,887 @@ +/** + * 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 com.wso2.openbanking.accelerator.consent.extensions.validate; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.exception.ConsentManagementException; +import com.wso2.openbanking.accelerator.common.util.CarbonUtils; +import com.wso2.openbanking.accelerator.common.util.ErrorConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentExtensionConstants; +import com.wso2.openbanking.accelerator.consent.extensions.common.ConsentServiceUtil; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionDataProvider; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestConstants; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentExtensionTestUtils; +import com.wso2.openbanking.accelerator.consent.extensions.utils.ConsentValidateTestConstants; +import com.wso2.openbanking.accelerator.consent.extensions.validate.impl.DefaultConsentValidator; +import com.wso2.openbanking.accelerator.consent.extensions.validate.impl.VRPSubmissionPayloadValidator; +import com.wso2.openbanking.accelerator.consent.extensions.validate.model.ConsentValidateData; +import com.wso2.openbanking.accelerator.consent.extensions.validate.model.ConsentValidationResult; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.AuthorizationResource; +import com.wso2.openbanking.accelerator.consent.mgt.dao.models.DetailedConsentResource; +import com.wso2.openbanking.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; +import org.joda.time.Instant; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.testng.Assert; +import org.testng.IObjectFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.ObjectFactory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +/** + * Test class for validating Variable Recurring Payment submission requests. + */ +@PrepareForTest({OpenBankingConfigParser.class, OpenBankingConfigParser.class, ConsentServiceUtil.class}) +@PowerMockIgnore({"com.wso2.openbanking.accelerator.consent.extensions.common.*", "net.minidev.*", + "jdk.internal.reflect.*"}) +public class VRPSubmissionTest { + VRPSubmissionPayloadValidator validator = new VRPSubmissionPayloadValidator(); + DefaultConsentValidator consentValidator; + @Mock + ConsentValidateData consentValidateDataMock; + @Mock + DetailedConsentResource detailedConsentResourceMock; + @Mock + ConsentCoreServiceImpl consentCoreServiceMock; + @Mock + ConsentValidationResult consentValidationResultMock; + Map resourceParams = new HashMap<>(); + JSONObject headers = new JSONObject(); + private static Map configMap; + Map consentAttributes = new HashMap<>(); + ArrayList authorizationResources = new ArrayList(); + + @BeforeClass + public void initClass() throws ReflectiveOperationException { + MockitoAnnotations.initMocks(this); + + //to execute util class initialization + new CarbonUtils(); + System.setProperty("some.property", "property.value"); + System.setProperty("carbon.home", "."); + ConsentExtensionTestUtils.injectEnvironmentVariable("CARBON_HOME", "."); + + configMap = new HashMap<>(); + configMap.put("ErrorURL", "https://localhost:8243/error"); + + consentValidator = new DefaultConsentValidator(); + consentValidateDataMock = mock(ConsentValidateData.class); + authorizationResources.add(getAuthorizationResource()); + detailedConsentResourceMock = mock(DetailedConsentResource.class); + consentCoreServiceMock = mock(ConsentCoreServiceImpl.class); + } + + @BeforeMethod + public void initMethod() { + + OpenBankingConfigParser openBankingConfigParserMock = mock(OpenBankingConfigParser.class); + doReturn(configMap).when(openBankingConfigParserMock).getConfiguration(); + + PowerMockito.mockStatic(OpenBankingConfigParser.class); + PowerMockito.when(OpenBankingConfigParser.getInstance()).thenReturn(openBankingConfigParserMock); + } + + @ObjectFactory + public IObjectFactory getObjectFactory() { + + return new org.powermock.modules.testng.PowerMockObjectFactory(); + } + @Test + public void testValidateInitiation() throws ParseException { + + JSONObject initPayload = ConsentExtensionTestUtils.getJsonPayload( + ConsentValidateTestConstants.VRP_INITIATION); + JSONObject subPayload = ConsentExtensionTestUtils.getJsonPayload( + ConsentValidateTestConstants.VRP_SUBMISSION); + + JSONObject validationResult = validator.validateInitiation( + ConsentExtensionTestUtils.getInitiationPayload(subPayload), + ConsentExtensionTestUtils.getInitiationPayload(initPayload)); + + Assert.assertTrue((Boolean) validationResult.get(ConsentExtensionConstants.IS_VALID_PAYLOAD)); + } + + @Test + public void testCreditorAccInInstruction() throws ParseException { + + JSONObject initPayload = ConsentExtensionTestUtils.getJsonPayload( + ConsentValidateTestConstants.VRP_INITIATION_WITHOUT_CREDITOR_ACC); + JSONObject subPayload = ConsentExtensionTestUtils.getJsonPayload( + ConsentValidateTestConstants.VRP_SUBMISSION); + + JSONObject validationResult = validator.validateCreditorAcc( + ConsentExtensionTestUtils.getInitiationPayload(subPayload), + ConsentExtensionTestUtils.getInitiationPayload(initPayload)); + + Assert.assertTrue((Boolean) validationResult.get(ConsentExtensionConstants.IS_VALID_PAYLOAD)); + } + + @Test + public void testValidateVRPSubmission() throws ParseException, ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertTrue(consentValidationResult.isValid()); + } + @Test + public void testValidateVRPSubmissionWithoutRisk() throws ParseException, ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_RISK); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.RISK_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testConsentValidateWithUserIdMismatch() { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionTestConstants.VALID_INITIATION_OBJECT).when(detailedConsentResourceMock) + .getReceipt(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn("psu1@wso2.com").when(consentValidateDataMock).getUserId(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.INVALID_USER_ID);; + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithInvalidStatus() { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentExtensionTestConstants.VALID_INITIATION_OBJECT).when(detailedConsentResourceMock) + .getReceipt(); + doReturn(ConsentExtensionConstants.AWAITING_AUTH_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.VRP_CONSENT_STATUS_INVALID); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_INVALID_CONSENT_STATUS); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithInvalidInstruction() throws ParseException, ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_INVALID_INSTRUCTION); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), + ErrorConstants.CREDITOR_ACC_SCHEME_NAME_MISMATCH); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithInvalidRisk() throws ParseException, ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_INVALID_RISK); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.RISK_PARAMETER_MISMATCH); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithoutInstruction() throws ParseException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_INSTRUCTION); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.INSTRUCTION_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + private Map getVRPConsentAttributes() { + consentAttributes.put(ConsentExtensionConstants.PAYMENT_TYPE, "domestic-vrp-consents"); + consentAttributes.put(ConsentExtensionConstants.MAXIMUM_INDIVIDUAL_AMOUNT, "100.00"); + consentAttributes.put(ConsentExtensionConstants.PERIOD_ALIGNMENT, "Consent"); + consentAttributes.put(ConsentExtensionConstants.PERIOD_TYPE, "Week"); + consentAttributes.put(ConsentExtensionConstants.LAST_PAYMENT_DATE, + Long.toString(ConsentValidateTestConstants.EXPIRATION_DATE.toEpochSecond())); + consentAttributes.put(ConsentExtensionConstants.AMOUNT, "100.00"); + + return consentAttributes; + } + + private AuthorizationResource getAuthorizationResource() { + return new AuthorizationResource(ConsentValidateTestConstants.CONSENT_ID, + ConsentValidateTestConstants.USER_ID, "awaitingAuthorization", + ConsentValidateTestConstants.SAMPLE_AUTHORIZATION_TYPE, Instant.now().getMillis()); + } + + @Test + public void testValidateVRPSubmissionWithoutCreditorAccount() throws ParseException, ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_CREDITOR_ACC); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.CREDITOR_ACC_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithDebtorAccountMisMatch() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_DEBTOR_ACC_MISMATCH); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.DEBTOR_ACC_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithoutRemittanceInfo() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), + ErrorConstants.REMITTANCE_INFO_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithRemittanceInfoMisMatch() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO_MISMATCH); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), + ErrorConstants.REMITTANCE_INFO_MISMATCH); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test(dataProvider = "VRPInvalidInitiationSubmissionPayloadsDataProvider", + dataProviderClass = ConsentExtensionDataProvider.class) + public void testValidateVRPSubmissionForInvalidInitiation(String payload) throws ParseException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE).parse(payload); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + // Using VRPInvalidInitiationSubmissionPayloadsDataProvider dataProvider three test scenarios are been tested. + // Relevant error messages will be returned respectively. + } + + @Test + public void testValidateVRPSubmissionWithIntegerInstructionIdentification() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_INTEGER_INSTRUCTION_IDENTIFICATION); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.INVALID_SUBMISSION_TYPE); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_INVALID); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithIntegerEndToEndIdentification() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_INTEGER_END_TO_IDENTIFICATION); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), + ErrorConstants.INVALID_END_TO_END_IDENTIFICATION_TYPE); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_INVALID); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithoutDebtorAccInSubmission() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION_WITHOUT_DEBTOR_ACC).when(detailedConsentResourceMock) + .getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_DEBTOR_ACC); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.DEBTOR_ACC_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testValidateVRPSubmissionWithoutCreditorAccInInitiation() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION_WITHOUT_CREDITOR_ACC).when(detailedConsentResourceMock). + getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITH_INSTRUCTION_CREDITOR_ACC); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.CREDITOR_ACC_NOT_FOUND); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.FIELD_MISSING); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test(dataProvider = "VRPInvalidSubmissionPayloadsDataProvider", + dataProviderClass = ConsentExtensionDataProvider.class) + public void testValidateVRPSubmissionForInvalidInstruction(String payload) throws ParseException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE).parse(payload); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + // Using the VRPInvalidSubmissionPayloadsDataProvider dataProvider five test scenarios are been tested. + // Relevant error messages will be returned respectively. + } + + @Test + public void testValidateVRPSubmissionWithInstructionRemittanceMismatch() throws ParseException, + ConsentManagementException { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentValidateTestConstants.VRP_INITIATION).when(detailedConsentResourceMock).getReceipt(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + + doReturn(getVRPConsentAttributes()).when(detailedConsentResourceMock).getConsentAttributes(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + doReturn(ConsentValidateTestConstants.VRP_PATH).when(consentValidateDataMock).getRequestPath(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.CONSENT_ID).when(consentValidateDataMock).getConsentId(); + JSONObject submissionPayload = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE) + .parse(ConsentValidateTestConstants.VRP_SUBMISSION_WITHOUT_REMITTANCE_INFO_MISMATCH); + doReturn(submissionPayload).when(consentValidateDataMock).getPayload(); + + doReturn(ConsentExtensionTestUtils.getConsentAttributes("vrp")) + .when(consentCoreServiceMock).getConsentAttributes(Mockito.anyString()); + doReturn(true).when(consentCoreServiceMock).deleteConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + doReturn(true).when(consentCoreServiceMock).storeConsentAttributes(Mockito.anyString(), + Mockito.>anyObject()); + + PowerMockito.mockStatic(ConsentServiceUtil.class); + PowerMockito.when(ConsentServiceUtil.getConsentService()).thenReturn(consentCoreServiceMock); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.REMITTANCE_INFO_MISMATCH); + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + + @Test + public void testConsentValidateVRPvWithInvalidConsentId() { + + doReturn(authorizationResources).when(detailedConsentResourceMock).getAuthorizationResources(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(detailedConsentResourceMock).getClientID(); + doReturn(detailedConsentResourceMock).when(consentValidateDataMock).getComprehensiveConsent(); + doReturn(ConsentExtensionConstants.VRP).when(detailedConsentResourceMock).getConsentType(); + doReturn(ConsentExtensionConstants.AUTHORIZED_STATUS).when(detailedConsentResourceMock).getCurrentStatus(); + doReturn(ConsentValidateTestConstants.INVALID_CONSENT_ID).when(detailedConsentResourceMock).getConsentID(); + doReturn(ConsentExtensionTestConstants.VALID_INITIATION_OBJECT).when(detailedConsentResourceMock) + .getReceipt(); + doReturn(resourceParams).when(consentValidateDataMock).getResourceParams(); + doReturn(headers).when(consentValidateDataMock).getHeaders(); + doReturn(ConsentValidateTestConstants.USER_ID).when(consentValidateDataMock).getUserId(); + doReturn(ConsentValidateTestConstants.CLIENT_ID).when(consentValidateDataMock).getClientId(); + + ConsentValidationResult consentValidationResult = new ConsentValidationResult(); + consentValidator.validate(consentValidateDataMock, consentValidationResult); + + Assert.assertFalse(consentValidationResult.isValid()); + Assert.assertEquals(consentValidationResult.getErrorMessage(), ErrorConstants.MSG_INVALID_CONSENT_ID);; + Assert.assertEquals(consentValidationResult.getErrorCode(), ErrorConstants.RESOURCE_CONSENT_MISMATCH); + Assert.assertEquals(consentValidationResult.getHttpCode(), 400); + } + +} + diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/resources/testng.xml b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/resources/testng.xml index 405a2646..ddc3905f 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/resources/testng.xml +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.extensions/src/test/resources/testng.xml @@ -24,6 +24,14 @@ + + + + + + + + diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/pom.xml b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/pom.xml index 6e3d2768..bae5d5ee 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/pom.xml +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -34,7 +32,7 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/ConsentCoreDAO.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/ConsentCoreDAO.java index 39609302..bc6b66ed 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/ConsentCoreDAO.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/ConsentCoreDAO.java @@ -148,6 +148,18 @@ boolean updateConsentMappingStatus(Connection connection, ArrayList mapp String mappingStatus) throws OBConsentDataUpdationException; + /** + * This method is used to update given consent mapping resource permissions. All the mapping resources of provided + * map will be updated with the new mapping permission provided. + * + * @param connection - Connection object + * @param mappingIDPermissionMap - A map of mapping IDs against new permissions + * @return - true if the update is successful + * @throws OBConsentDataUpdationException - Thrown of a database level error occurs + */ + boolean updateConsentMappingPermission(Connection connection, Map mappingIDPermissionMap) + throws OBConsentDataUpdationException; + /** * This method is used to update a given authorization object. The status of the authorization resource provided * will be updated with the new status. @@ -217,7 +229,7 @@ ConsentAttributes getConsentAttributes(Connection connection, String consentID) * @param connection connection object * @param attributeName attribute name * @return a map with the conesnt ID and the related attribute value - * @throws OBConsentDataRetrievalException + * @throws OBConsentDataRetrievalException thrown if a database error occurs */ Map getConsentAttributesByName(Connection connection, String attributeName) throws OBConsentDataRetrievalException; @@ -229,7 +241,7 @@ Map getConsentAttributesByName(Connection connection, String att * @param attributeName attribute name * @param attributeValue attribute value * @return Consent ID related to the given attribute key and value - * @throws OBConsentDataRetrievalException + * @throws OBConsentDataRetrievalException `thrown if a database error occurs */ ArrayList getConsentIdByConsentAttributeNameAndValue(Connection connection, String attributeName, String attributeValue) @@ -424,7 +436,7 @@ boolean updateConsentValidityTime(Connection connection, String consentID, long * relevant to each history record * @param amendmentReason A string that indicates the reason that caused the amendment of the consent * @return true if insertion successful - * @throws OBConsentDataUpdationException + * @throws OBConsentDataInsertionException thrown if any error occurs in the process */ boolean storeConsentAmendmentHistory(Connection connection, String historyID, long timestamp, String recordID, String consentDataType, String changedAttributesJsonString, String amendmentReason) diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/constants/ConsentMgtDAOConstants.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/constants/ConsentMgtDAOConstants.java index 01e7f70e..171e4910 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/constants/ConsentMgtDAOConstants.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/constants/ConsentMgtDAOConstants.java @@ -92,6 +92,8 @@ public class ConsentMgtDAOConstants { " database"; public static final String CONSENT_MAPPING_STATUS_UPDATE_ERROR_MSG = "Error occurred while updating consent " + "mapping status in the database"; + public static final String CONSENT_MAPPING_PERMISSION_UPDATE_ERROR_MSG = "Error occurred while updating consent " + + "mapping permission in the database"; public static final String CONSENT_AUTHORIZATION_STATUS_UPDATE_ERROR_MSG = "Error occurred while updating " + "authorization status in the database"; public static final String CONSENT_AUTHORIZATION_USER_UPDATE_ERROR_MSG = "Error occurred while updating " + diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/ConsentCoreDAOImpl.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/ConsentCoreDAOImpl.java index 629d3804..9d225758 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/ConsentCoreDAOImpl.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/ConsentCoreDAOImpl.java @@ -445,6 +445,42 @@ public boolean updateConsentMappingStatus(Connection connection, ArrayList mappingIDPermissionMap) + throws OBConsentDataUpdationException { + + int[] result; + String updateConsentMappingPermissionQuery = + sqlStatements.getUpdateConsentMappingPermissionPreparedStatement(); + + try (PreparedStatement updateConsentMappingPermissionPreparedStmt = + connection.prepareStatement(updateConsentMappingPermissionQuery)) { + + log.debug("Setting parameters to prepared statement to update consent mapping permissions"); + + for (String mappingID : mappingIDPermissionMap.keySet()) { + updateConsentMappingPermissionPreparedStmt.setString(1, mappingIDPermissionMap.get(mappingID)); + updateConsentMappingPermissionPreparedStmt.setString(2, mappingID); + updateConsentMappingPermissionPreparedStmt.addBatch(); + } + + // With result, we can determine whether the updating was successful or not + result = updateConsentMappingPermissionPreparedStmt.executeBatch(); + } catch (SQLException e) { + log.error(ConsentMgtDAOConstants.CONSENT_MAPPING_PERMISSION_UPDATE_ERROR_MSG, e); + throw new OBConsentDataUpdationException( + ConsentMgtDAOConstants.CONSENT_MAPPING_PERMISSION_UPDATE_ERROR_MSG, e); + } + + // An empty array or an array with value -3 means the batch execution is failed + if (result.length != 0 && IntStream.of(result).noneMatch(value -> value == -3)) { + log.debug("Updated the consent mapping permissions of matching records successfully"); + return true; + } else { + throw new OBConsentDataUpdationException("Failed to update consent mapping permissions properly."); + } + } + @Override public AuthorizationResource updateAuthorizationStatus(Connection connection, String authorizationID, String newAuthorizationStatus) diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/OracleConsentCoreDAOImpl.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/OracleConsentCoreDAOImpl.java index 50d796a4..0e98044d 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/OracleConsentCoreDAOImpl.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/impl/OracleConsentCoreDAOImpl.java @@ -232,9 +232,8 @@ void setConsentDataToDetailedConsentInSearchResponse(ResultSet resultSet, .split(GROUP_BY_SEPARATOR)).distinct().findFirst(); Optional validityTime = Arrays.stream(resultSet.getString(ConsentMgtDAOConstants.VALIDITY_TIME) .split(GROUP_BY_SEPARATOR)).distinct().findFirst(); - Optional recurringIndicator = Arrays.stream( - resultSet.getString(ConsentMgtDAOConstants.RECURRING_INDICATOR) - .split(GROUP_BY_SEPARATOR)).distinct().findFirst(); + Optional recurringIndicator = + Optional.of(resultSet.getBoolean(ConsentMgtDAOConstants.RECURRING_INDICATOR)); if (consentId.isPresent() && clientId.isPresent()) { detailedConsentResource.setConsentID(consentId.get()); @@ -249,7 +248,7 @@ void setConsentDataToDetailedConsentInSearchResponse(ResultSet resultSet, consentUpdatedTime.ifPresent(e -> detailedConsentResource.setUpdatedTime(Long.parseLong(e))); frequency.ifPresent(e -> detailedConsentResource.setConsentFrequency(Integer.parseInt(e))); validityTime.ifPresent(e -> detailedConsentResource.setValidityPeriod(Long.parseLong(e))); - recurringIndicator.ifPresent(e -> detailedConsentResource.setRecurringIndicator(Boolean.parseBoolean(e))); + recurringIndicator.ifPresent(detailedConsentResource::setRecurringIndicator); } protected void setAuthorizationDataInResponseForGroupedQuery(ArrayList diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtCommonDBQueries.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtCommonDBQueries.java index fbbec890..48a27b56 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtCommonDBQueries.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtCommonDBQueries.java @@ -71,6 +71,11 @@ public String getUpdateConsentMappingStatusPreparedStatement() { return "UPDATE OB_CONSENT_MAPPING SET MAPPING_STATUS = ? WHERE MAPPING_ID = ?"; } + public String getUpdateConsentMappingPermissionPreparedStatement() { + + return "UPDATE OB_CONSENT_MAPPING SET PERMISSION = ? WHERE MAPPING_ID = ?"; + } + public String getUpdateAuthorizationStatusPreparedStatement() { return "UPDATE OB_CONSENT_AUTH_RESOURCE SET AUTH_STATUS = ?, UPDATED_TIME = ? WHERE AUTH_ID = ?"; @@ -325,8 +330,8 @@ public String getGetConsentHistoryPreparedStatement(String whereClause) { /** * SQL query for delete consent attributes. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for delete consent attributes */ public String getDeleteConsentAttributeByConsentIdPreparedStatement(boolean executeOnRetentionTables) { @@ -340,8 +345,8 @@ public String getDeleteConsentAttributeByConsentIdPreparedStatement(boolean exec /** * SQL query for delete consent file. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for delete consent file */ public String getDeleteConsentFileResourcePreparedStatement(boolean executeOnRetentionTables) { @@ -355,8 +360,8 @@ public String getDeleteConsentFileResourcePreparedStatement(boolean executeOnRet /** * SQL query for delete consent mapping by auth id. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for delete consent mapping by auth id */ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOnRetentionTables) { @@ -371,8 +376,8 @@ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOn /** * SQL query for delete auth resource. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for delete auth resource */ public String getDeleteAuthorizationResourcePreparedStatement(boolean executeOnRetentionTables) { @@ -386,8 +391,8 @@ public String getDeleteAuthorizationResourcePreparedStatement(boolean executeOnR /** * SQL query for consent status audit record. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for consent status audit record */ public String getDeleteConsentStatusAuditRecordsPreparedStatement(boolean executeOnRetentionTables) { @@ -401,8 +406,8 @@ public String getDeleteConsentStatusAuditRecordsPreparedStatement(boolean execut /** * SQL query for delete consent. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query for delete consent */ public String getDeleteConsentPreparedStatement(boolean executeOnRetentionTables) { @@ -416,8 +421,8 @@ public String getDeleteConsentPreparedStatement(boolean executeOnRetentionTables /** * SQL query for get list of consent_ids. - * @param fetchFromRetentionTables - * @return + * @param fetchFromRetentionTables whether to fetch from retention tables + * @return SQL query for get list of consent_ids */ public String getListOfConsentIdsPreparedStatement(boolean fetchFromRetentionTables) { @@ -432,10 +437,10 @@ public String getListOfConsentIdsPreparedStatement(boolean fetchFromRetentionTab /** * SQL query for get consent status audit records by consentIds. * @param whereClause conditions - * @param shouldLimit - * @param shouldOffset - * @param fetchFromRetentionTables - * @return + * @param shouldLimit whether to consider the Limit parameter + * @param shouldOffset whether to consider the Offset parameter + * @param fetchFromRetentionTables whether to fetch from retention tables + * @return SQL query for get consent status audit records by consentIds */ public String getConsentStatusAuditRecordsByConsentIdsPreparedStatement(String whereClause, boolean shouldLimit, boolean shouldOffset, diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtMssqlDBQueries.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtMssqlDBQueries.java index f164effa..d9b68208 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtMssqlDBQueries.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtMssqlDBQueries.java @@ -145,8 +145,8 @@ public String getSearchConsentsPreparedStatement(String whereClause, boolean sho /** * SQL query for delete consent mapping by auth id. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables execute on retention tables + * @return SQL query */ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOnRetentionTables) { @@ -163,10 +163,10 @@ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOn /** * SQL query for get consent status audit records by consentIds. * @param whereClause conditions - * @param shouldLimit - * @param shouldOffset - * @param fetchFromRetentionTables - * @return + * @param shouldLimit limit + * @param shouldOffset offset + * @param fetchFromRetentionTables fetch from retention tables + * @return SQL query */ public String getConsentStatusAuditRecordsByConsentIdsPreparedStatement(String whereClause, boolean shouldLimit, boolean shouldOffset, diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtOracleDBQueries.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtOracleDBQueries.java index 1de250aa..d321977c 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtOracleDBQueries.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtOracleDBQueries.java @@ -148,8 +148,8 @@ public String getSearchConsentsPreparedStatement(String whereClause, boolean sho /** * SQL query for delete consent mapping by auth id. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables whether to execute on retention tables + * @return SQL query to delete consent mapping by auth id */ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOnRetentionTables) { @@ -166,10 +166,10 @@ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOn /** * SQL query for get consent status audit records by consentIds. * @param whereClause conditions - * @param shouldLimit - * @param shouldOffset - * @param fetchFromRetentionTables - * @return + * @param shouldLimit whether limit should be applied + * @param shouldOffset whether offset should be applied + * @param fetchFromRetentionTables whether to fetch from retention tables + * @return SQL query to retrieve consent status audit records by consentIds */ public String getConsentStatusAuditRecordsByConsentIdsPreparedStatement(String whereClause, boolean shouldLimit, boolean shouldOffset, diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtPostgresDBQueries.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtPostgresDBQueries.java index 8b905623..ec5af0d2 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtPostgresDBQueries.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/queries/ConsentMgtPostgresDBQueries.java @@ -212,8 +212,8 @@ public String getSearchConsentsPreparedStatement(String whereClause, boolean sho /** * SQL query for delete consent mapping by auth id. - * @param executeOnRetentionTables - * @return + * @param executeOnRetentionTables flag to execute on retention tables + * @return SQL query for delete consent mapping by auth id */ public String getDeleteConsentMappingByAuthIdPreparedStatement(boolean executeOnRetentionTables) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/utils/ConsentDAOUtils.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/utils/ConsentDAOUtils.java index c928065d..5974f4cb 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/utils/ConsentDAOUtils.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/dao/utils/ConsentDAOUtils.java @@ -160,8 +160,8 @@ public static String constructAuthSearchPreparedStatement(Map ap /** * Method to construct where clause for consent status audit search condition. - * @param consentIDs - * @return + * @param consentIDs List of consent IDs + * @return Filter condition for consent status audit */ public static String constructConsentAuditRecordSearchPreparedStatement(ArrayList consentIDs) { @@ -232,8 +232,8 @@ public static TreeMap determineOrderOfParamsToSet(String pre /** * Method to construct excluded statuses search condition. * - * @param statusesEligibleForExpiration - * @return + * @param statusesEligibleForExpiration List of statuses eligible for expiration + * @return Filter condition for excluded statuses */ public static String constructStatusesEligibleForExpirationCondition(List statusesEligibleForExpiration) { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/test/resources/dbScripts/h2.sql b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/test/resources/dbScripts/h2.sql index 4ad9e806..b54f6c72 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/test/resources/dbScripts/h2.sql +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.dao/src/test/resources/dbScripts/h2.sql @@ -60,7 +60,7 @@ CREATE TABLE IF NOT EXISTS OB_CONSENT_FILE ( CREATE TABLE IF NOT EXISTS OB_CONSENT_ATTRIBUTE ( CONSENT_ID VARCHAR(255) NOT NULL, ATT_KEY VARCHAR(255) NOT NULL, - ATT_VALUE VARCHAR(255) NOT NULL, + ATT_VALUE VARCHAR(1023) NOT NULL, PRIMARY KEY(CONSENT_ID, ATT_KEY), CONSTRAINT FK_OB_CONSENT_ATTRIBUTE FOREIGN KEY (CONSENT_ID) REFERENCES OB_CONSENT (CONSENT_ID) ); diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/pom.xml b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/pom.xml index 947f853d..e6aaeb14 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/pom.xml +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/pom.xml @@ -17,13 +17,11 @@ ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -35,7 +33,7 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -50,7 +48,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao provided diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/ConsentCoreService.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/ConsentCoreService.java index cca72fbd..067c2b70 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/ConsentCoreService.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/ConsentCoreService.java @@ -218,6 +218,7 @@ boolean revokeConsentWithReason(String consentID, String revokedConsentStatus, S * @param consentType consent type * @param applicableStatusToRevoke the status that a consent should have for revoking * @param revokedConsentStatus the status should be updated the consent with after revoking + * @param shouldRevokeTokens the check to revoke tokens or not when revoking consent * @return returns true if successful * @throws ConsentManagementException thrown if an error occurs in the process */ @@ -368,6 +369,11 @@ boolean reAuthorizeExistingAuthResource(String consentID, String authID, String * @param consentID consent ID * @param userID user ID * @param accountIDsMapWithPermissions account IDs with relative permissions + * @param currentConsentStatus current status of the consent for creating audit record + * @param newConsentStatus new consent status after re authorization + * @param newExistingAuthStatus new status of the existing authorizations + * @param newAuthStatus new status of the new authorization + * @param newAuthType new authorization type * @return true if all operations are successful * @throws ConsentManagementException thrown if any error occurs in the process */ @@ -406,6 +412,7 @@ AuthorizationResource createConsentAuthorization(AuthorizationResource authoriza * used to represent permissions related to each accountID. * * @param authID authorization ID + * @param accountIDsMapWithPermissions account IDs with relative permissions * @return returns the list of created consent mapping resources * @throws ConsentManagementException thrown if any error occurs */ @@ -433,6 +440,17 @@ ArrayList createConsentAccountMappings(String authID, */ boolean updateAccountMappingStatus(ArrayList accountMappingIDs, String newMappingStatus) throws ConsentManagementException; + + /** + * This method is used to update the permissions of the provided account mappings. + * + * @param mappingIDPermissionMap - A map of mapping IDs against new permissions + * @return - true if update is successful + * @throws ConsentManagementException - Thrown if a DAO level error occurs + */ + boolean updateAccountMappingPermission(Map mappingIDPermissionMap) throws + ConsentManagementException; + /** * This method is used to search detailed consents for the given lists of parameters. Following optional lists * can be passed to retrieve detailed consents. The search will be performed according to the provided input. Any @@ -508,6 +526,7 @@ ArrayList searchDetailedConsents(ArrayList cons /** * This method is used to bind user and accounts to the consent. * + * @param consentResource consent resource * @param userID user ID * @param authID ID of the authorization resource * @param accountIDsMapWithPermissions account IDs list with relevant permissions @@ -523,6 +542,7 @@ boolean bindUserAccountsToConsent(ConsentResource consentResource, String userID /** * This method is used to bind user and accounts to the consent where permissions for each account is not relevant. * + * @param consentResource consent resource * @param userID user ID * @param authID ID of the authorization resource * @param accountIDs account IDs list @@ -544,6 +564,7 @@ public boolean bindUserAccountsToConsent(ConsentResource consentResource, String * @param consentID consent ID * @param userID user ID * @return a list of authorization resources + * @throws ConsentManagementException thrown if any error occurs in the process */ ArrayList searchAuthorizations(String consentID, String userID) throws ConsentManagementException; @@ -553,6 +574,7 @@ ArrayList searchAuthorizations(String consentID, String u * * @param consentID consent ID * @return a list of authorization resources + * @throws ConsentManagementException thrown if any error occurs in the process */ ArrayList searchAuthorizations(String consentID) throws ConsentManagementException; @@ -562,6 +584,7 @@ ArrayList searchAuthorizations(String consentID) * * @param userID user ID * @return a list of authorization resources + * @throws ConsentManagementException thrown if any error occurs in the process */ ArrayList searchAuthorizationsForUser(String userID) throws ConsentManagementException; @@ -584,10 +607,10 @@ ConsentResource amendConsentData(String consentID, String consentReceipt, Long c /** * This method is used to update status of the consent for a given consentId and userId. - * @param consentId - * @param newConsentStatus - * @return - * @throws ConsentManagementException + * @param consentId consent ID + * @param newConsentStatus new consent status + * @return updated consent resource + * @throws ConsentManagementException thrown if any error occurs in the process */ ConsentResource updateConsentStatus(String consentId, String newConsentStatus) throws ConsentManagementException; @@ -595,9 +618,9 @@ ConsentResource updateConsentStatus(String consentId, String newConsentStatus) /** * This method is used to fetch consents which has a expiring time as a consent attribute * (eligible for expiration). - * @param statusesEligibleForExpiration - * @return - * @throws ConsentManagementException + * @param statusesEligibleForExpiration statuses eligible for expiration + * @return list of consents eligible for expiration + * @throws ConsentManagementException thrown if any error occurs in the process */ ArrayList getConsentsEligibleForExpiration(String statusesEligibleForExpiration) throws ConsentManagementException; @@ -620,7 +643,6 @@ AuthorizationResource updateAuthorizationStatus(String authorizationId, String n * * @param authorizationID the authorization ID of the authorization resource that needs to be updated * @param userID the user of the authorization resource - * @return * @throws ConsentManagementException thrown if any error occurs while updating */ void updateAuthorizationUser(String authorizationID, String userID) @@ -677,8 +699,8 @@ Map getConsentAmendmentHistoryData(String consen /** * This method is used to sync the retention database with purged consents from consent database. - * @return - * @throws ConsentManagementException + * @return true if the sync is successful + * @throws ConsentManagementException thrown if any error occurs in the process */ boolean syncRetentionDatabaseWithPurgedConsent() throws ConsentManagementException; diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/ConsentCoreServiceImpl.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/ConsentCoreServiceImpl.java index fa532da2..0a8f0504 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/ConsentCoreServiceImpl.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/main/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/ConsentCoreServiceImpl.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -347,24 +347,27 @@ public boolean revokeConsentWithReason(String consentID, String revokedConsentSt ArrayList authorizationResources = retrievedDetailedConsentResource .getAuthorizationResources(); - String consentUserID = ""; + // Get all users of the consent + Set consentUserIDSet = new HashSet<>(); if (authorizationResources != null && !authorizationResources.isEmpty()) { - consentUserID = authorizationResources.get(0).getUserID(); + for (AuthorizationResource authorizationResource : authorizationResources) { + consentUserIDSet.add(authorizationResource.getUserID()); + } } - if (StringUtils.isBlank(consentUserID)) { + if (consentUserIDSet.isEmpty()) { log.error("User ID is required for token revocation, cannot proceed"); throw new ConsentManagementException("User ID is required for token revocation, cannot " + "proceed"); } - if (!isValidUserID(userID, consentUserID)) { + if (!isValidUserID(userID, consentUserIDSet)) { final String errorMsg = "Requested UserID and Consent UserID do not match, cannot proceed."; log.error(errorMsg + ", request UserID: " + userID.replaceAll("[\r\n]", "") + - ", Consent UserID: " + consentUserID.replaceAll("[\r\n]", "")); + " is not a member of the consent user list"); throw new ConsentManagementException(errorMsg); } - revokeTokens(retrievedDetailedConsentResource, consentUserID); + revokeTokens(retrievedDetailedConsentResource, userID); } ArrayList consentMappingResources = retrievedDetailedConsentResource @@ -506,9 +509,10 @@ public boolean revokeExistingApplicableConsents(String clientID, String userID, // Update account mappings as inactive log.debug("Deactivating account mappings"); - consentCoreDAO.updateConsentMappingStatus(connection, accountMappingIDsList, - ConsentCoreServiceConstants.INACTIVE_MAPPING_STATUS); - + if (accountMappingIDsList.size() > 0) { + consentCoreDAO.updateConsentMappingStatus(connection, accountMappingIDsList, + ConsentCoreServiceConstants.INACTIVE_MAPPING_STATUS); + } //Commit transaction DatabaseUtil.commitTransaction(connection); log.debug(ConsentCoreServiceConstants.TRANSACTION_COMMITTED_LOG_MSG); @@ -1247,6 +1251,35 @@ public boolean updateAccountMappingStatus(ArrayList accountMappingIDs, S } } + @Override + public boolean updateAccountMappingPermission(Map mappingIDPermissionMap) throws + ConsentManagementException { + + if (mappingIDPermissionMap.isEmpty()) { + log.error("Account mapping IDs are not provided, cannot proceed"); + throw new ConsentManagementException("Cannot proceed since account mapping IDs are not provided"); + } + + Connection connection = DatabaseUtil.getDBConnection(); + try { + ConsentCoreDAO consentCoreDAO = ConsentStoreInitializer.getInitializedConsentCoreDAOImpl(); + try { + log.debug("Updating consent account mapping permissions for given mapping IDs"); + consentCoreDAO.updateConsentMappingPermission(connection, mappingIDPermissionMap); + DatabaseUtil.commitTransaction(connection); + log.debug(ConsentCoreServiceConstants.TRANSACTION_COMMITTED_LOG_MSG); + return true; + } catch (OBConsentDataUpdationException e) { + log.error(ConsentCoreServiceConstants.DATA_UPDATE_ROLLBACK_ERROR_MSG, e); + DatabaseUtil.rollbackTransaction(connection); + throw new ConsentManagementException(ConsentCoreServiceConstants.DATA_UPDATE_ROLLBACK_ERROR_MSG, e); + } + } finally { + log.debug(ConsentCoreServiceConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtil.closeConnection(connection); + } + } + @Override public ArrayList searchDetailedConsents(ArrayList consentIDs, ArrayList clientIDs, @@ -2169,6 +2202,7 @@ public Map getConsentAmendmentHistoryData(String consentAmendmentHistory = processConsentAmendmentHistoryData( consentAmendmentHistoryRetrievalResult, currentConsentResource); } + DatabaseUtil.commitTransaction(connection); return consentAmendmentHistory; } catch (OBConsentDataRetrievalException e) { log.error(ConsentCoreServiceConstants.DATA_RETRIEVE_ERROR_MSG, e); @@ -2582,12 +2616,12 @@ public void revokeTokens(DetailedConsentResource detailedConsentResource, String } } - private boolean isValidUserID(String requestUserID, String consentUserID) { + private boolean isValidUserID(String requestUserID, Set consentUserIDSet) { if (StringUtils.isEmpty(requestUserID)) { // userId not present in request query parameters, can use consentUserID to revoke tokens return true; } - return requestUserID.equals(consentUserID); + return consentUserIDSet.contains(requestUserID); } @Generated(message = "Excluded from code coverage since used for testing purposes") diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/OBConsentMgtCoreServiceTests.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/OBConsentMgtCoreServiceTests.java index b694b867..360eafe6 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/OBConsentMgtCoreServiceTests.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/impl/OBConsentMgtCoreServiceTests.java @@ -1154,6 +1154,26 @@ public void testDeactivateAccountMappingsRollback() throws Exception { consentCoreServiceImpl.deactivateAccountMappings(ConsentMgtServiceTestData.UNMATCHED_MAPPING_IDS); } + @Test + public void testUpdateAccountMappingPermissionWithEmptyMap() { + + try { + consentCoreServiceImpl.updateAccountMappingPermission(new HashMap<>()); + Assert.fail("Expected ConsentManagementException to be thrown"); + } catch (ConsentManagementException e) { + Assert.assertEquals(e.getMessage(), "Cannot proceed since account mapping IDs are not provided"); + } + } + + @Test + public void testUpdateAccountMappingPermission() throws Exception { + + Mockito.doReturn(true).when(mockedConsentCoreDAO).updateConsentMappingPermission(Mockito.any(), + Mockito.any()); + Assert.assertTrue(consentCoreServiceImpl + .updateAccountMappingPermission(ConsentMgtServiceTestData.SAMPLE_MAPPING_ID_PERMISSION_MAP)); + } + @Test public void testSearchConsents() throws Exception { diff --git a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/util/ConsentMgtServiceTestData.java b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/util/ConsentMgtServiceTestData.java index 08cfb646..08a3eab8 100644 --- a/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/util/ConsentMgtServiceTestData.java +++ b/open-banking-accelerator/components/consent-management/com.wso2.openbanking.accelerator.consent.mgt.service/src/test/java/com/wso2/openbanking/accelerator/consent/mgt/service/util/ConsentMgtServiceTestData.java @@ -183,6 +183,11 @@ public class ConsentMgtServiceTestData { } }; + public static final HashMap SAMPLE_MAPPING_ID_PERMISSION_MAP = new HashMap() {{ + put("mapping_id_1", "permission_1"); + put("mapping_id_2", "permission_2"); + }}; + private static final ArrayList SAMPLE_CONSENT_RECEIPTS_LIST = new ArrayList() { { add("{\"element1\": \"value1\"}"); diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/pom.xml b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/pom.xml index 72ea5539..3d7a58f5 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/pom.xml +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/pom.xml @@ -18,8 +18,8 @@ open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -62,15 +62,15 @@ powermock-api-mockito - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -81,7 +81,7 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/constants/EventNotificationConstants.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/constants/EventNotificationConstants.java index 12124024..835e2248 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/constants/EventNotificationConstants.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/constants/EventNotificationConstants.java @@ -114,5 +114,5 @@ public class EventNotificationConstants { public static final String EVENT_SUBSCRIPTION_NOT_FOUND = "Event subscription not found."; public static final String EVENT_SUBSCRIPTIONS_NOT_FOUND = "Event subscriptions not found for the given client id."; public static final String ERROR_HANDLING_EVENT_SUBSCRIPTION = "Error occurred while handling the event " + - "subscription request"; + "subscription request"; } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAO.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAO.java index 41c80dd2..26325d13 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAO.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAO.java @@ -35,69 +35,71 @@ public interface AggregatedPollingDAO { * This method is to update the notification status by ID, allowed values are. * OPEN,ACK and ERR * - * @param notificationId - * @param notificationStatus - * @return - * @throws OBEventNotificationException + * @param notificationId Notification ID to update + * @param notificationStatus Notification status to update + * @return Update is success or not + * @throws OBEventNotificationException Exception when updating notification status by ID */ Boolean updateNotificationStatusById(String notificationId, String notificationStatus) throws OBEventNotificationException; /** - * This method is to store event notifications in the OB_NOTIFICATION table. - * @param notificationError - * @return - * @throws OBEventNotificationException + * This method is to store event notifications error details in the OB_NOTIFICATION table. + * + * @param notificationError Notification error details + * @return Stored event notifications error details + * @throws OBEventNotificationException Exception when storing event notifications error details */ Map storeErrorNotification(NotificationError notificationError) throws OBEventNotificationException; /** * This method is to retrieve given number of notifications in the OB_NOTIFICATION table by client and status. - * @param clientId - * @param status - * @param max - * @return - * @throws OBEventNotificationException + * + * @param clientId Client ID to retrieve notifications + * @param status Notification status to retrieve + * @param max Maximum number of notifications to retrieve + * @return List of notifications by client and status + * @throws OBEventNotificationException Exception when retrieving notifications by client ID and status */ List getNotificationsByClientIdAndStatus(String clientId, String status, int max) throws OBEventNotificationException; /** * This method is to retrieve notifications by NotificationID. - * @param notificationId * - * @return - * @throws OBEventNotificationException + * @param notificationId Notification ID to retrieve + * @return List of notifications by notification ID + * @throws OBEventNotificationException Exception when retrieving notifications by notification ID */ List getEventsByNotificationID(String notificationId) throws OBEventNotificationException; /** * This method is to retrieve notifications in the OB_NOTIFICATION table by status. - * @param status * - * @return List - * @throws OBEventNotificationException + * @param status Notification status to retrieve + * @return List of notifications by status + * @throws OBEventNotificationException Exception when retrieving notifications by status */ List getNotificationsByStatus(String status) throws OBEventNotificationException; /** * This method is to retrieve notificationsCount by ClientId and Status. - * @param clientId - * @param eventStatus * - * @return - * @throws OBEventNotificationException + * @param clientId Client ID to retrieve notifications + * @param eventStatus Notification status to retrieve + * @return List of notifications by status and client id + * @throws OBEventNotificationException Exception when retrieving notification count by client ID and status */ int getNotificationCountByClientIdAndStatus(String clientId, String eventStatus) throws OBEventNotificationException; /** * This method is to retrieve the notification status. - * @param notificationId * - * @return - * @throws OBEventNotificationException + * @param notificationId Notification ID to retrieve + * @return Notification status by notification ID + * @throws OBEventNotificationException Exception when retrieving notification status */ boolean getNotificationStatus(String notificationId) throws OBEventNotificationException; } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAOImpl.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAOImpl.java index 57708a1e..a14b74b7 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAOImpl.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/AggregatedPollingDAOImpl.java @@ -61,7 +61,7 @@ public Boolean updateNotificationStatusById(String notificationId, String notifi Connection connection = DatabaseUtil.getDBConnection(); if (log.isDebugEnabled()) { log.debug(String.format("Database connection is established for updating notification with " + - "ID : '%s' in the database. ", notificationId)); + "ID : '%s' in the database. ", notificationId.replaceAll("[\r\n]", ""))); } try { connection.setAutoCommit(false); @@ -78,32 +78,31 @@ public Boolean updateNotificationStatusById(String notificationId, String notifi if (affectedRows != 0) { connection.commit(); if (log.isDebugEnabled()) { - log.debug("Updated notification with Notification ID : " + notificationId); + log.debug(String.format("Updated notification with Notification ID '%s'", + notificationId.replaceAll("[\r\n]", ""))); } return true; } else { if (log.isDebugEnabled()) { - log.debug("Failed updating notification with ID : " + notificationId); + log.debug(String.format("Failed updating notification with ID : '%s'", + notificationId.replaceAll("[\r\n]", ""))); } return false; } } catch (SQLException e) { connection.rollback(savepoint); - log.error(String.format(EventNotificationConstants.DB_ERROR_UPDATING, notificationId), e); + log.error(String.format(EventNotificationConstants.DB_ERROR_UPDATING, + notificationId.replaceAll("[\r\n]", "")), e); throw new OBEventNotificationException(String.format(EventNotificationConstants.DB_ERROR_UPDATING, notificationId)); } } catch (SQLException e) { - if (log.isDebugEnabled()) { - log.debug("SQL exception when updating notification status", e); - } + log.debug("SQL exception when updating notification status", e); throw new OBEventNotificationException("Database error while closing the connection to the" + " the database."); } finally { - if (log.isDebugEnabled()) { - log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); - } + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); DatabaseUtil.closeConnection(connection); } } @@ -119,8 +118,9 @@ public Map storeErrorNotification(NotificationError n connection.setAutoCommit(false); if (log.isDebugEnabled()) { - log.debug("Database connection is established for storing error notification with ID : " - + notificationError.getNotificationId()); + log.debug(String.format("Database connection is established for storing error notification with ID" + + " : '%s' in the database. ", + notificationError.getNotificationId().replaceAll("[\r\n]", ""))); } final String storeErrorNotificationQuery = sqlStatements.storeErrorNotificationQuery(); @@ -138,14 +138,14 @@ public Map storeErrorNotification(NotificationError n if (affectedRows == 1) { connection.commit(); if (log.isDebugEnabled()) { - log.debug("Successfully stored error notification with ID : " + - notificationError.getNotificationId()); + log.debug(String.format("Successfully stored error notification with ID:'%s'.", + notificationError.getNotificationId().replaceAll("[\r\n]", ""))); } response.put(notificationError.getNotificationId(), notificationError); } else { if (log.isDebugEnabled()) { - log.debug(EventNotificationConstants.DB_FAILED_ERROR_NOTIFICATION_STORING - + notificationError.getNotificationId()); + log.debug(String.format("Failed store error notification with ID:'%s'.", + notificationError.getNotificationId().replaceAll("[\r\n]", ""))); } throw new OBEventNotificationException(EventNotificationConstants. DB_FAILED_ERROR_NOTIFICATION_STORING + notificationError.getNotificationId()); @@ -176,7 +176,8 @@ public List getNotificationsByClientIdAndStatus(String clientId notificationList = new ArrayList<>(); if (log.isDebugEnabled()) { - log.debug(String.format(EventNotificationConstants.DB_CONN_ESTABLISHED, clientId)); + log.debug(String.format(EventNotificationConstants.DB_CONN_ESTABLISHED, + clientId.replaceAll("[\r\n]", ""))); } final String sql = sqlStatements.getMaxNotificationsQuery(); @@ -215,12 +216,12 @@ public List getNotificationsByClientIdAndStatus(String clientId if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT, - clientId)); + clientId.replaceAll("[\r\n]", ""))); } } else { if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, - clientId)); + clientId.replaceAll("[\r\n]", ""))); } } } @@ -268,7 +269,7 @@ public List getEventsByNotificationID(String notificationId) (EventNotificationConstants.EVENT_TYPE)); event.setEventInformation(EventNotificationServiceUtil. getEventJSONFromString(eventsResultSet.getString - (EventNotificationConstants.EVENT_INFO))); + (EventNotificationConstants.EVENT_INFO))); eventList.add(event); } eventsResultSet.close(); @@ -276,21 +277,23 @@ public List getEventsByNotificationID(String notificationId) if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.RETRIEVED_EVENTS_NOTIFICATION, - notificationId)); + notificationId.replaceAll("[\r\n]", ""))); } } else { if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.NO_EVENTS_NOTIFICATION_ID, - notificationId)); + notificationId.replaceAll("[\r\n]", ""))); } } } catch (ParseException e) { - log.error(String.format(EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, notificationId), e); + log.error(String.format(EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, + notificationId.replaceAll("[\r\n]", "")), e); throw new OBEventNotificationException(String.format ( EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, notificationId), e); } } catch (SQLException e) { - log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); + log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, + notificationId.replaceAll("[\r\n]", "")), e); throw new OBEventNotificationException(String.format (EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); } @@ -337,7 +340,8 @@ public List getNotificationsByStatus(String status) throws OBEv notificationResultSet.close(); getNotificationsPreparedStatement.close(); if (log.isDebugEnabled()) { - log.debug(EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT); + log.debug( + EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT); } } else { if (log.isDebugEnabled()) { @@ -378,7 +382,7 @@ public int getNotificationCountByClientIdAndStatus(String clientId, String event if (log.isDebugEnabled()) { log.debug(String.format("Retrieved notification count for client ID: '%s'. ", - clientId)); + clientId.replaceAll("[\r\n]", ""))); } return count; @@ -386,7 +390,7 @@ public int getNotificationCountByClientIdAndStatus(String clientId, String event if (log.isDebugEnabled()) { log.debug(String.format( EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, - clientId)); + clientId.replaceAll("[\r\n]", ""))); } return 0; @@ -394,8 +398,7 @@ public int getNotificationCountByClientIdAndStatus(String clientId, String event } } catch (SQLException e) { throw new OBEventNotificationException(String.format - (EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, - clientId), e); + (EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, clientId), e); } } finally { log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); @@ -422,13 +425,14 @@ public boolean getNotificationStatus(String notificationId) throws OBEventNotifi isOpenStatus = true; } - return isOpenStatus; - } else { - if (log.isDebugEnabled()) { - log.debug("No notifications found for notification ID : " + notificationId); - } - } - } + return isOpenStatus; + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("No notifications found for notification ID - '%s'", + notificationId.replaceAll("[\r\n]", ""))); + } + } + } } catch (SQLException e) { throw new OBEventNotificationException(String.format ("Error occurred while retrieving status for the notifications ID : '%s'.", diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventPublisherDAO.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventPublisherDAO.java index 7e59e93c..0ff62185 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventPublisherDAO.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventPublisherDAO.java @@ -32,11 +32,11 @@ public interface EventPublisherDAO { /** * This method is used to persist event notifications in the database. - * @param connection - * @param notificationDTO - * @param eventsList + * @param connection Database connection + * @param notificationDTO Notification details DTO + * @param eventsList List of notification events * @return NotificationID of the saved notification. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when persisting event notification data */ String persistEventNotification(Connection connection, NotificationDTO notificationDTO, ArrayList eventsList) throws OBEventNotificationException; diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java index 5e1fd28d..dc41501e 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java @@ -35,7 +35,7 @@ public interface EventSubscriptionDAO { * @param connection Database connection. * @param eventSubscription EventSubscription object. * @return EventSubscription object. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when storing event subscription */ EventSubscription storeEventSubscription(Connection connection, EventSubscription eventSubscription) throws OBEventNotificationException; @@ -47,7 +47,7 @@ EventSubscription storeEventSubscription(Connection connection, EventSubscriptio * @param subscriptionId Subscription ID. * @param eventTypes Event types to be stored. * @return List of strings with subscribed event types. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when storing subscribed event types */ List storeSubscribedEventTypes(Connection connection, String subscriptionId, List eventTypes) throws OBEventNotificationException; @@ -58,7 +58,7 @@ List storeSubscribedEventTypes(Connection connection, String subscriptio * @param connection Database connection. * @param subscriptionId Subscription ID. * @return EventSubscription model. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when retrieving event subscription by subscription ID */ EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, String subscriptionId) throws OBEventNotificationException; @@ -69,7 +69,7 @@ EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, St * @param connection Database connection. * @param clientId Client ID. * @return List of EventSubscription models. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when retrieving event subscriptions by client ID */ List getEventSubscriptionsByClientId(Connection connection, String clientId) throws OBEventNotificationException; @@ -80,7 +80,7 @@ List getEventSubscriptionsByClientId(Connection connection, S * @param connection Database connection. * @param eventType Event type that need to be subscribed by the retrieving subscriptions. * @return List of EventSubscription models. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when retrieving event subscriptions by event type */ List getEventSubscriptionsByEventType(Connection connection, String eventType) throws OBEventNotificationException; @@ -91,7 +91,7 @@ List getEventSubscriptionsByEventType(Connection connection, * @param connection Database connection. * @param eventSubscription eventSubscription object. * @return true if update was successful. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when updating event subscription */ Boolean updateEventSubscription(Connection connection, EventSubscription eventSubscription) throws OBEventNotificationException; @@ -102,7 +102,7 @@ Boolean updateEventSubscription(Connection connection, EventSubscription eventSu * @param connection Database connection. * @param subscriptionId Subscription ID. * @return true if deletion was successful. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when deleting event subscription */ Boolean deleteEventSubscription(Connection connection, String subscriptionId) throws OBEventNotificationException; @@ -112,7 +112,7 @@ Boolean updateEventSubscription(Connection connection, EventSubscription eventSu * @param connection Database connection. * @param subscriptionId subscription ID. * @return true if deletion was successful. - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when deleting subscribed event types */ Boolean deleteSubscribedEventTypes(Connection connection, String subscriptionId) throws OBEventNotificationException; diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionSqlStatements.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionSqlStatements.java index 855cbde9..ee06d675 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionSqlStatements.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/EventSubscriptionSqlStatements.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-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 @@ -61,7 +61,7 @@ public String updateEventSubscriptionQuery() { } public String updateEventSubscriptionStatusQuery() { - return "UPDATE OB_NOTIFICATION_SUBSCRIPTION SET STATUS = ? WHERE SUBSCRIPTION_ID = ? && STATUS = 'CREATED'"; + return "UPDATE OB_NOTIFICATION_SUBSCRIPTION SET STATUS = ? WHERE SUBSCRIPTION_ID = ? AND STATUS = 'CREATED'"; } public String deleteSubscribedEventTypesQuery() { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java new file mode 100644 index 00000000..e3d56cff --- /dev/null +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java @@ -0,0 +1,197 @@ +/** + * 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 com.wso2.openbanking.accelerator.event.notifications.service.dao; + +import com.wso2.openbanking.accelerator.event.notifications.service.constants.EventNotificationConstants; +import com.wso2.openbanking.accelerator.event.notifications.service.exceptions.OBEventNotificationException; +import com.wso2.openbanking.accelerator.event.notifications.service.model.EventSubscription; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * Postgres SQL EventSubscriptionDAO Impl. + */ +public class PostgreSqlEventSubscriptionDAOImpl extends EventSubscriptionDAOImpl { + + private static final Log log = LogFactory.getLog(PostgreSqlEventSubscriptionDAOImpl.class); + + public PostgreSqlEventSubscriptionDAOImpl(EventSubscriptionSqlStatements sqlStatements) { + super(sqlStatements); + } + + @Override + public EventSubscription storeEventSubscription(Connection connection, EventSubscription eventSubscription) + throws OBEventNotificationException { + + int storeSubscriptionAffectedRows; + + UUID subscriptionId = UUID.randomUUID(); + long unixTime = Instant.now().getEpochSecond(); + eventSubscription.setSubscriptionId(subscriptionId.toString()); + eventSubscription.setTimeStamp(unixTime); + eventSubscription.setStatus(EventNotificationConstants.CREATED); + + final String sql = sqlStatements.storeEventSubscriptionQuery(); + try (PreparedStatement storeEventSubscriptionStatement = connection.prepareStatement(sql)) { + storeEventSubscriptionStatement.setString(1, eventSubscription.getSubscriptionId()); + storeEventSubscriptionStatement.setString(2, eventSubscription.getClientId()); + storeEventSubscriptionStatement.setString(3, eventSubscription.getCallbackUrl()); + storeEventSubscriptionStatement.setLong(4, eventSubscription.getTimeStamp()); + storeEventSubscriptionStatement.setString(5, eventSubscription.getSpecVersion()); + storeEventSubscriptionStatement.setString(6, eventSubscription.getStatus()); + storeEventSubscriptionStatement.setObject(7, eventSubscription.getRequestData(), + java.sql.Types.OTHER); + storeSubscriptionAffectedRows = storeEventSubscriptionStatement.executeUpdate(); + if (storeSubscriptionAffectedRows == 0) { + log.error("Failed to store the event notification subscription."); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when storing the event types of the subscription", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + return eventSubscription; + } + + @Override + public List getEventSubscriptionsByClientId(Connection connection, String clientId) + throws OBEventNotificationException { + List retrievedSubscriptions = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionsByClientIdQuery(); + try (PreparedStatement getEventSubscriptionsByClientIdStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getEventSubscriptionsByClientIdStatement.setString(1, clientId); + try (ResultSet resultSet = getEventSubscriptionsByClientIdStatement.executeQuery()) { + if (resultSet.isBeforeFirst()) { + while (resultSet.next()) { + EventSubscription eventSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + mapResultSetToEventSubscription(eventSubscription, resultSet); + resultSet.previous(); + while (resultSet.next()) { + if (eventSubscription.getSubscriptionId().equals(resultSet. + getString(EventNotificationConstants.SUBSCRIPTION_ID))) { + if (resultSet.getString(EventNotificationConstants.EVENT_TYPE) != null) { + eventTypes.add(resultSet.getString(EventNotificationConstants.EVENT_TYPE)); + } + } else { + resultSet.previous(); + break; + } + } + if (!eventTypes.isEmpty()) { + eventSubscription.setEventTypes(eventTypes); + } + retrievedSubscriptions.add(eventSubscription); + } + log.debug("Retrieved the event notification subscriptions successfully."); + } + return retrievedSubscriptions; + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTIONS); + } + } + + @Override + public EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, String subscriptionId) + throws OBEventNotificationException { + EventSubscription retrievedSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionBySubscriptionIdQuery(); + try (PreparedStatement getEventSubscriptionBySubscriptionIdStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getEventSubscriptionBySubscriptionIdStatement.setString(1, subscriptionId); + try (ResultSet resultSet = getEventSubscriptionBySubscriptionIdStatement.executeQuery()) { + if (resultSet.next()) { + mapResultSetToEventSubscription(retrievedSubscription, resultSet); + resultSet.beforeFirst(); // Reset the cursor position to the beginning of the result set. + while (resultSet.next()) { + String eventType = resultSet.getString(EventNotificationConstants.EVENT_TYPE); + if (eventType != null) { + eventTypes.add(eventType); + } + } + if (!eventTypes.isEmpty()) { + retrievedSubscription.setEventTypes(eventTypes); + } + } else { + log.error("No event notification subscription found for the given subscription id."); + throw new OBEventNotificationException( + EventNotificationConstants.EVENT_SUBSCRIPTION_NOT_FOUND); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + return retrievedSubscription; + } + + @Override + public Boolean updateEventSubscription(Connection connection, EventSubscription eventSubscription) + throws OBEventNotificationException { + boolean isUpdated = false; + final String sql = sqlStatements.updateEventSubscriptionQuery(); + try (PreparedStatement updateEventSubscriptionStatement = connection.prepareStatement(sql)) { + updateEventSubscriptionStatement.setString(1, eventSubscription.getCallbackUrl()); + updateEventSubscriptionStatement.setLong(2, Instant.now().getEpochSecond()); + updateEventSubscriptionStatement.setObject(3, eventSubscription.getRequestData(), + java.sql.Types.OTHER); + updateEventSubscriptionStatement.setString(4, eventSubscription.getSubscriptionId()); + int affectedRows = updateEventSubscriptionStatement.executeUpdate(); + if (affectedRows > 0) { + log.debug("Event notification subscription is successfully updated."); + isUpdated = true; + } + } catch (SQLException e) { + log.error("SQL exception when updating event notification subscription", e); + throw new OBEventNotificationException(EventNotificationConstants.ERROR_UPDATING_EVENT_SUBSCRIPTION); + } + return isUpdated; + } + + private void mapResultSetToEventSubscription(EventSubscription response, ResultSet resultSet) throws SQLException { + response.setSubscriptionId(resultSet.getString(EventNotificationConstants.SUBSCRIPTION_ID)); + response.setClientId(resultSet.getString(EventNotificationConstants.CLIENT_ID)); + response.setCallbackUrl(resultSet.getString(EventNotificationConstants.CALLBACK_URL)); + response.setTimeStamp(resultSet.getLong(EventNotificationConstants.TIME_STAMP)); + response.setSpecVersion(resultSet.getString(EventNotificationConstants.SPEC_VERSION)); + response.setStatus(resultSet.getString(EventNotificationConstants.STATUS)); + response.setRequestData(resultSet.getString(EventNotificationConstants.REQUEST)); + } +} diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlPollingDAOImpl.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlPollingDAOImpl.java index 7144e4e7..0421e4ec 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlPollingDAOImpl.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlPollingDAOImpl.java @@ -59,7 +59,8 @@ public List getNotificationsByClientIdAndStatus(String clientId notificationList = new ArrayList<>(); if (log.isDebugEnabled()) { - log.debug(String.format(EventNotificationConstants.DB_CONN_ESTABLISHED, clientId)); + log.debug(String.format(EventNotificationConstants.DB_CONN_ESTABLISHED, + clientId.replaceAll("[\r\n]", ""))); } final String sql = sqlStatements.getMaxNotificationsQuery(); @@ -99,13 +100,13 @@ public List getNotificationsByClientIdAndStatus(String clientId if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT, - clientId)); + clientId.replaceAll("[\r\n]", ""))); } } else { if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, - clientId)); + clientId.replaceAll("[\r\n]", ""))); } } } @@ -162,21 +163,23 @@ public List getEventsByNotificationID(String notificationId) if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.RETRIEVED_EVENTS_NOTIFICATION, - notificationId)); + notificationId.replaceAll("[\r\n]", ""))); } } else { if (log.isDebugEnabled()) { log.debug(String.format(EventNotificationConstants.NO_EVENTS_NOTIFICATION_ID, - notificationId)); + notificationId.replaceAll("[\r\n]", ""))); } } } catch (ParseException e) { - log.error(String.format(EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, notificationId), e); + log.error(String.format(EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, + notificationId.replaceAll("[\r\n]", "")), e); throw new OBEventNotificationException(String.format ( EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, notificationId), e); } } catch (SQLException e) { - log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); + log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, + notificationId.replaceAll("[\r\n]", "")), e); throw new OBEventNotificationException(String.format (EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java index 8a9f9c60..df5bd14a 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java @@ -43,6 +43,12 @@ public void setEventCreationService(EventCreationService eventCreationService) { this.eventCreationService = eventCreationService; } + /** + * This method is used to publish OB events in the accelerator database. + * + * @param notificationCreationDTO Notification details DTO + * @return EventCreationResponse Response after event creation + */ public EventCreationResponse publishOBEvent(NotificationCreationDTO notificationCreationDTO) { //validate if the resourceID is existing @@ -53,6 +59,7 @@ public EventCreationResponse publishOBEvent(NotificationCreationDTO notification try { consentResource = consentCoreService.getConsent(notificationCreationDTO.getResourceId(), false); + if (log.isDebugEnabled()) { log.debug("Consent resource available for resource ID " + consentResource.getConsentID().replaceAll("[\r\n]", "")); @@ -71,9 +78,9 @@ public EventCreationResponse publishOBEvent(NotificationCreationDTO notification } catch (OBEventNotificationException e) { log.error("Invalid client ID", e); - eventCreationResponse.setErrorResponse(String.format(String.format("A client was not found" + + eventCreationResponse.setErrorResponse(String.format("A client was not found" + " for the client id : '%s' in the database. ", - notificationCreationDTO.getClientId()))); + notificationCreationDTO.getClientId().replaceAll("[\r\n]", ""))); eventCreationResponse.setStatus(EventNotificationConstants.BAD_REQUEST); return eventCreationResponse; } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java index 063a2dca..9372f04d 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java @@ -51,8 +51,8 @@ public void setEventPollingService(EventPollingService eventPollingService) { /** * This method is used to Poll Events as per request params. - * @param eventPollingRequest - * @return + * @param eventPollingRequest JSON request for event polling + * @return EventPollingResponse */ public EventPollingResponse pollEvents(JSONObject eventPollingRequest) { @@ -66,7 +66,7 @@ public EventPollingResponse pollEvents(JSONObject eventPollingRequest) { log.error("Invalid client ID", e); eventPollingResponse.setStatus(EventNotificationConstants.BAD_REQUEST); eventPollingResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( - EventNotificationConstants.INVALID_REQUEST, String.format("A client was not found" + + EventNotificationConstants.INVALID_REQUEST, String.format("A client was not found" + " for the client id : '%s' in the database.. ", eventPollingDTO.getClientId()))); return eventPollingResponse; } @@ -89,7 +89,7 @@ public EventPollingResponse pollEvents(JSONObject eventPollingRequest) { /** * This method will map the eventPollingRequest JSON to EventPollingDTO. - * @param eventPollingRequest + * @param eventPollingRequest JSON request for event polling * @return EventPollingDTO */ public EventPollingDTO mapPollingRequest(JSONObject eventPollingRequest) { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java index 406d2a64..e8a281d4 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java @@ -28,7 +28,7 @@ import net.minidev.json.JSONObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.http.HttpStatus; +import org.apache.http.HttpStatus; import java.util.ArrayList; import java.util.List; @@ -65,13 +65,13 @@ public EventSubscriptionResponse createEventSubscription(EventSubscriptionDTO ev try { EventSubscription createEventSubscriptionResponse = eventSubscriptionService. createEventSubscription(eventSubscription); - eventSubscriptionResponse.setStatus(HttpStatus.CREATED.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_CREATED); eventSubscriptionResponse. setResponseBody(mapSubscriptionModelToResponseJson(createEventSubscriptionResponse)); return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while creating event subscription", e); - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; @@ -99,17 +99,17 @@ public EventSubscriptionResponse getEventSubscription(String clientId, String su try { EventSubscription eventSubscription = eventSubscriptionService. getEventSubscriptionBySubscriptionId(subscriptionId); - eventSubscriptionResponse.setStatus(HttpStatus.OK.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_OK); eventSubscriptionResponse.setResponseBody(mapSubscriptionModelToResponseJson(eventSubscription)); return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while retrieving event subscription", e); if (e.getMessage().equals(EventNotificationConstants.EVENT_SUBSCRIPTION_NOT_FOUND)) { - eventSubscriptionResponse.setStatus(HttpStatus.BAD_REQUEST.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_BAD_REQUEST); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); } else { - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); } @@ -139,12 +139,12 @@ public EventSubscriptionResponse getAllEventSubscriptions(String clientId) { for (EventSubscription eventSubscription : eventSubscriptionList) { eventSubscriptionResponseList.add(mapSubscriptionModelToResponseJson(eventSubscription)); } - eventSubscriptionResponse.setStatus(HttpStatus.OK.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_OK); eventSubscriptionResponse.setResponseBody(eventSubscriptionResponseList); return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while retrieving event subscriptions", e); - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; @@ -175,12 +175,12 @@ public EventSubscriptionResponse getEventSubscriptionsByEventType(String clientI for (EventSubscription eventSubscription : eventSubscriptionList) { eventSubscriptionResponseList.add(mapSubscriptionModelToResponseJson(eventSubscription)); } - eventSubscriptionResponse.setStatus(HttpStatus.OK.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_OK); eventSubscriptionResponse.setResponseBody(eventSubscriptionResponseList); return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while retrieving event subscriptions", e); - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; @@ -208,13 +208,13 @@ public EventSubscriptionResponse updateEventSubscription(EventSubscriptionDTO ev try { Boolean isUpdated = eventSubscriptionService.updateEventSubscription(eventSubscription); if (!isUpdated) { - eventSubscriptionResponse.setStatus(HttpStatus.BAD_REQUEST.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_BAD_REQUEST); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, "Event subscription not found.")); return eventSubscriptionResponse; } - eventSubscriptionResponse.setStatus(HttpStatus.OK.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_OK); EventSubscription eventSubscriptionUpdateResponse = eventSubscriptionService. getEventSubscriptionBySubscriptionId(eventSubscriptionUpdateRequestDto.getSubscriptionId()); eventSubscriptionResponse. @@ -222,7 +222,7 @@ public EventSubscriptionResponse updateEventSubscription(EventSubscriptionDTO ev return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while updating event subscription", e); - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; @@ -247,17 +247,17 @@ public EventSubscriptionResponse deleteEventSubscription(String clientId, String try { Boolean isDeleted = eventSubscriptionService.deleteEventSubscription(subscriptionId); if (!isDeleted) { - eventSubscriptionResponse.setStatus(HttpStatus.BAD_REQUEST.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_BAD_REQUEST); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, "Event subscription not found")); return eventSubscriptionResponse; } - eventSubscriptionResponse.setStatus(HttpStatus.NO_CONTENT.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_NO_CONTENT); return eventSubscriptionResponse; } catch (OBEventNotificationException e) { log.error("Error occurred while deleting event subscription", e); - eventSubscriptionResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; @@ -277,7 +277,7 @@ private EventSubscriptionResponse validateClientId(String clientId) { } catch (OBEventNotificationException e) { log.error("Invalid client ID", e); EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); - eventSubscriptionResponse.setStatus(HttpStatus.BAD_REQUEST.value()); + eventSubscriptionResponse.setStatus(HttpStatus.SC_BAD_REQUEST); eventSubscriptionResponse.setErrorResponse(EventNotificationServiceUtil.getErrorDTO( EventNotificationConstants.INVALID_REQUEST, e.getMessage())); return eventSubscriptionResponse; diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java index 3f1c6877..671a64c6 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java @@ -30,7 +30,7 @@ public interface EventCreationServiceHandler { /** * This method is used to publish OB events in the accelerator database. The method is a generic * method that is used to persist data into the OB_NOTIFICATION and OB_NOTIFICATION_EVENT tables. - * @param notificationCreationDTO + * @param notificationCreationDTO Notification details DTO * @return For successful request the API will return a JSON with the notificationID */ EventCreationResponse publishOBEvent(NotificationCreationDTO notificationCreationDTO); diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventNotificationPersistenceServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventNotificationPersistenceServiceHandler.java index dfea1457..720d89a8 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventNotificationPersistenceServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventNotificationPersistenceServiceHandler.java @@ -39,6 +39,15 @@ public static EventNotificationPersistenceServiceHandler getInstance() { return instance; } + /** + * This method is to persist authorization revoke event. + * + * @param clientId - client ID + * @param resourceId - resource ID + * @param notificationType - notification type + * @param notificationInfo - notification info + * @return EventCreationResponse + */ public EventCreationResponse persistRevokeEvent(String clientId, String resourceId, String notificationType, JSONObject notificationInfo) { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java index 7a714db2..30a02dfe 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java @@ -32,14 +32,14 @@ public interface EventPollingServiceHandler { * This method follows the IETF Specification for SET delivery over HTTP. * The method supports event acknowledgment in both positive and negative. * Also, can be used to POLL for available OPEN notifications. - * @param eventPollingRequest + * @param eventPollingRequest JSON request for event polling * @return EventPollingResponse to the polling endpoint. */ EventPollingResponse pollEvents(JSONObject eventPollingRequest); /** * This method is used to map the eventPollingRequest to EventPollingDTO. - * @param eventPollingRequest + * @param eventPollingRequest JSON request for event polling * @return eventPollingDTO with the request parameters. */ EventPollingDTO mapPollingRequest(JSONObject eventPollingRequest); diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/internal/EventNotificationComponent.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/internal/EventNotificationComponent.java index aa7a95c1..7b813677 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/internal/EventNotificationComponent.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/internal/EventNotificationComponent.java @@ -63,6 +63,7 @@ protected void activate(ComponentContext context) { /** * Setters for the descendent OSGI services of the EventNotificationComponent. * This is added to run the EventNotification OSGI component after the Common module + * @param openBankingConfigurationService OpenBankingConfigurationService */ @Reference( service = OpenBankingConfigurationService.class, @@ -89,6 +90,10 @@ public void unsetConfigService(OpenBankingConfigurationService openBankingConfig unbind = "unsetOAuth2Service" ) + /** + * Setters for the descendent OSGI services of the EventNotificationComponent. + * @param oAuth2Service OAuth2Service + */ public void setOAuth2Service(OAuth2Service oAuth2Service) { } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/model/Notification.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/model/Notification.java index fba9b08e..1a7aacf6 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/model/Notification.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/model/Notification.java @@ -111,7 +111,12 @@ public void setIss(String iss) { /** * This method is to convert the class to a JSONObject. - **/ + * @param notification Notification + * @return JSONObject + * @throws IOException IOException when converting the class to JSONObject + * @throws JOSEException JOSEException when converting the class to JSONObject + * @throws IdentityOAuth2Exception IdentityOAuth2Exception when converting the class to JSONObject + */ public static JsonNode getJsonNode(Notification notification) throws IOException, JOSEException, IdentityOAuth2Exception { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/persistence/EventSubscriptionStoreInitializer.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/persistence/EventSubscriptionStoreInitializer.java index 3d0f63ad..a3d040bf 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/persistence/EventSubscriptionStoreInitializer.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/persistence/EventSubscriptionStoreInitializer.java @@ -23,6 +23,7 @@ import com.wso2.openbanking.accelerator.event.notifications.service.dao.EventSubscriptionDAO; import com.wso2.openbanking.accelerator.event.notifications.service.dao.EventSubscriptionDAOImpl; import com.wso2.openbanking.accelerator.event.notifications.service.dao.EventSubscriptionSqlStatements; +import com.wso2.openbanking.accelerator.event.notifications.service.dao.PostgreSqlEventSubscriptionDAOImpl; import com.wso2.openbanking.accelerator.event.notifications.service.exceptions.OBEventNotificationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -52,7 +53,7 @@ public static EventSubscriptionDAO initializeSubscriptionDAO() throws OBEventNot if (driverName.contains(MYSQL) || driverName.contains(H2)) { eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); } else if (driverName.contains(POSTGRE)) { - eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); + eventSubscriptionDao = new PostgreSqlEventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); } else if (driverName.contains(MSSQL)) { eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); } else if (driverName.contains(ORACLE)) { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/realtime/service/RealtimeEventNotificationRequestGenerator.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/realtime/service/RealtimeEventNotificationRequestGenerator.java index c996b09c..f9e6bf89 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/realtime/service/RealtimeEventNotificationRequestGenerator.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/realtime/service/RealtimeEventNotificationRequestGenerator.java @@ -32,6 +32,8 @@ public interface RealtimeEventNotificationRequestGenerator { * This method is to generate realtime event notification payload. To generate custom values * for the body this method should be extended. * + * @param notificationDTO Notification details DTO + * @param eventSET Event set * @return String payload */ String getRealtimeEventNotificationPayload(NotificationDTO notificationDTO, String eventSET); @@ -40,7 +42,7 @@ public interface RealtimeEventNotificationRequestGenerator { * This method is to generate realtime event notification request headers. To generate custom values * for the body this method should be extended. * - * @return Map headers + * @return Map of headers */ Map getAdditionalHeaders(); } diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventCreationService.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventCreationService.java index 466e0f33..3ccc63ec 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventCreationService.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventCreationService.java @@ -48,11 +48,10 @@ public class EventCreationService { /** * The publishOBEventNotification methods will call the dao layer to persist the event - * notifications - * event polling request. - * @param notificationCreationDTO - * - * @throws OBEventNotificationException + * notifications for event polling request. + * @param notificationCreationDTO Notification Creation DTO + * @return Event Response + * @throws OBEventNotificationException Exception when persisting event notification data */ public String publishOBEventNotification(NotificationCreationDTO notificationCreationDTO) throws OBEventNotificationException { @@ -84,7 +83,8 @@ public String publishOBEventNotification(NotificationCreationDTO notificationCre /** * The getEvents method is used to get the NotificationEvents Array list from payload. * - * @param notificationEvents + * @param notificationEvents Notification Events to convert + * @return Event notification List */ @Generated(message = "Private methods invoked when calling referred method") private ArrayList getEvents(Map notificationEvents) { @@ -104,7 +104,8 @@ private ArrayList getEvents(Map notificat /** * The getNotification method is used to get the NotificationDAO from payload. * - * @param notificationCreationDTO + * @param notificationCreationDTO Notification Creation DTO + * @return Notification Details */ @Generated(message = "Private methods invoked when calling referred method") private NotificationDTO getNotification(NotificationCreationDTO notificationCreationDTO) { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventNotificationGenerator.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventNotificationGenerator.java index fc24e51e..8b0e50ea 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventNotificationGenerator.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventNotificationGenerator.java @@ -35,10 +35,11 @@ public interface EventNotificationGenerator { /** * This method is to generate event notification body. To generate custom values * for the body this method should be extended. - * @param notificationDTO - * @param notificationEventList - * @return - * @throws OBEventNotificationException + * @param notificationDTO Notification details DTO + * @param notificationEventList List of notification events + * + * @return Event Notification Body + * @throws OBEventNotificationException Exception when generating event notification body */ Notification generateEventNotificationBody(NotificationDTO notificationDTO, List notificationEventList) throws OBEventNotificationException; diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventPollingService.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventPollingService.java index a823288a..8490a9f8 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventPollingService.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventPollingService.java @@ -50,9 +50,9 @@ public class EventPollingService { /** * The pollEvents methods will return the Aggregated Polling Response for * event polling request. - * @param eventPollingDTO - * - * @throws OBEventNotificationException + * @param eventPollingDTO Event polling request DTO + * @return AggregatedPollingResponse Aggregated Polling Response + * @throws OBEventNotificationException Exception when polling events */ public AggregatedPollingResponse pollEvents(EventPollingDTO eventPollingDTO) throws OBEventNotificationException { @@ -107,13 +107,13 @@ public AggregatedPollingResponse pollEvents(EventPollingDTO eventPollingDTO) if (notificationList.isEmpty()) { if (log.isDebugEnabled()) { log.debug(String.format("No OB Event Notifications available for for the client " + - "with ID : '%s'.", eventPollingDTO.getClientId())); + "with ID : '%s'.", eventPollingDTO.getClientId().replaceAll("[\r\n]", ""))); } aggregatedPollingResponse.setStatus(EventNotificationConstants.NOT_FOUND); } else { if (log.isDebugEnabled()) { log.debug(String.format("OB Event Notifications available for the client " + - "with ID : '%s'.", eventPollingDTO.getClientId())); + "with ID : '%s'.", eventPollingDTO.getClientId().replaceAll("[\r\n]", ""))); } aggregatedPollingResponse.setStatus(EventNotificationConstants.OK); diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventSubscriptionService.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventSubscriptionService.java index 20e9d55d..1d561c01 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventSubscriptionService.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/service/EventSubscriptionService.java @@ -43,7 +43,8 @@ public class EventSubscriptionService { * This method will call the dao layer to persist the event subscription. * * @param eventSubscription event subscription object that needs to be persisted - * @throws OBEventNotificationException + * @return event subscription object that is persisted + * @throws OBEventNotificationException if an error occurred while persisting the event subscription */ public EventSubscription createEventSubscription(EventSubscription eventSubscription) throws OBEventNotificationException { @@ -78,7 +79,8 @@ public EventSubscription createEventSubscription(EventSubscription eventSubscrip * This method will call the dao layer to retrieve a single event subscription. * * @param subscriptionId subscription id of the event subscription - * @throws OBEventNotificationException + * @return event subscription object that is retrieved + * @throws OBEventNotificationException if an error occurred while retrieving the event subscription */ public EventSubscription getEventSubscriptionBySubscriptionId(String subscriptionId) throws OBEventNotificationException { @@ -101,7 +103,8 @@ public EventSubscription getEventSubscriptionBySubscriptionId(String subscriptio * This method will call the dao layer to retrieve all event subscriptions of a client. * * @param clientId client id of the event subscription - * @throws OBEventNotificationException + * @return list of event subscriptions that are retrieved + * @throws OBEventNotificationException if an error occurred while retrieving the event subscriptions */ public List getEventSubscriptionsByClientId(String clientId) throws OBEventNotificationException { @@ -122,7 +125,8 @@ public List getEventSubscriptionsByClientId(String clientId) * This method will call the dao layer to retrieve all event subscriptions by event type. * * @param eventType event type that needs to be subscribed by the retrieving event subscriptions. - * @throws OBEventNotificationException + * @return list of event subscriptions that are retrieved + * @throws OBEventNotificationException if an error occurred while retrieving the event subscriptions */ public List getEventSubscriptionsByClientIdAndEventType(String eventType) throws OBEventNotificationException { @@ -144,7 +148,8 @@ public List getEventSubscriptionsByClientIdAndEventType(Strin * This method will call the dao layer to update an event subscription. * * @param eventSubscription event subscription object that needs to be updated - * @throws OBEventNotificationException + * @return true if the event subscription is updated successfully + * @throws OBEventNotificationException if an error occurred while updating the event subscription */ public Boolean updateEventSubscription(EventSubscription eventSubscription) throws OBEventNotificationException { @@ -206,7 +211,8 @@ public Boolean updateEventSubscription(EventSubscription eventSubscription) * This method will call the dao layer to delete an event subscription. * * @param subscriptionId subscription id of the event subscription - * @throws OBEventNotificationException + * @return true if the event subscription is deleted successfully + * @throws OBEventNotificationException if an error occurred while deleting the event subscription */ public Boolean deleteEventSubscription(String subscriptionId) throws OBEventNotificationException { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java index 4e0fd1eb..a83a9cc7 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/main/java/com/wso2/openbanking/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java @@ -92,7 +92,7 @@ public static String getCustomNotificationPayload(JsonNode jsonNode) { * Method to get event JSON from eventInformation payload string. * @param eventInformation String event Information * @return JSONObject converted event json - * @throws ParseException + * @throws ParseException Exception when parsing event information */ public static JSONObject getEventJSONFromString(String eventInformation) throws ParseException { @@ -103,7 +103,7 @@ public static JSONObject getEventJSONFromString(String eventInformation) throws /** * Validate if the client ID is existing. * @param clientId client ID of the TPP - * @throws OBEventNotificationException + * @throws OBEventNotificationException Exception when validating client ID */ @Generated(message = "Excluded since this needs OAuth2Util service provider") public static void validateClientId(String clientId) throws OBEventNotificationException { diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImplTests.java b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImplTests.java new file mode 100644 index 00000000..e2aa9aa1 --- /dev/null +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/java/com/wso2/openbanking/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImplTests.java @@ -0,0 +1,382 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. + * + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. + */ + +package com.wso2.openbanking.accelerator.event.notifications.service.dao; + +import com.wso2.openbanking.accelerator.common.util.DatabaseUtil; +import com.wso2.openbanking.accelerator.event.notifications.service.constants.EventNotificationConstants; +import com.wso2.openbanking.accelerator.event.notifications.service.constants.EventNotificationTestConstants; +import com.wso2.openbanking.accelerator.event.notifications.service.exceptions.OBEventNotificationException; +import com.wso2.openbanking.accelerator.event.notifications.service.model.EventSubscription; +import com.wso2.openbanking.accelerator.event.notifications.service.utils.EventNotificationTestUtils; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.when; + +/** + * Test class for EventSubscriptionDAOImpl. + */ +@PowerMockIgnore("jdk.internal.reflect.*") +@PrepareForTest(DatabaseUtil.class) +public class PostgreSqlEventSubscriptionDAOImplTests extends PowerMockTestCase { + private static Connection mockedConnection; + private PreparedStatement mockedPreparedStatement; + + PostgreSqlEventSubscriptionDAOImpl eventSubscriptionDAOImpl = new PostgreSqlEventSubscriptionDAOImpl( + new EventSubscriptionSqlStatements()); + + @BeforeMethod + public void mock() throws OBEventNotificationException { + mockedConnection = Mockito.mock(Connection.class); + mockedPreparedStatement = Mockito.mock(PreparedStatement.class); + PowerMockito.mockStatic(DatabaseUtil.class); + PowerMockito.when(DatabaseUtil.getDBConnection()).thenReturn(mockedConnection); + } + + @Test + public void testStoreEventSubscription() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(1); + EventSubscription sampleEventSubscription = EventNotificationTestUtils.getSampleEventSubscription(); + + EventSubscription result = eventSubscriptionDAOImpl.storeEventSubscription(mockedConnection, + sampleEventSubscription); + + Assert.assertNotNull(sampleEventSubscription.getSubscriptionId()); + Assert.assertNotNull(sampleEventSubscription.getTimeStamp()); + Assert.assertEquals("CREATED", result.getStatus()); + } + + @Test(expectedExceptions = OBEventNotificationException.class) + public void testStoreEventSubscriptionDBError() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenThrow(new SQLException()); + + eventSubscriptionDAOImpl.storeEventSubscription(mockedConnection, + EventNotificationTestUtils.getSampleEventSubscription()); + } + + @Test + public void testStoreSubscribedEventTypes() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeBatch()).thenReturn(new int[]{1, 1, 1}); + List sampleEventTypes = EventNotificationTestUtils.getSampleStoredEventTypes(); + + List result = eventSubscriptionDAOImpl.storeSubscribedEventTypes(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, sampleEventTypes); + + Assert.assertEquals(sampleEventTypes, result); + } + + @Test + public void testStoreSubscribedEventTypesFailure() throws SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeBatch()).thenReturn(new int[]{0, 1, 1}); + List sampleEventTypes = EventNotificationTestUtils.getSampleStoredEventTypes(); + + Assert.assertThrows(OBEventNotificationException.class, () -> eventSubscriptionDAOImpl. + storeSubscribedEventTypes(mockedConnection, EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + sampleEventTypes)); + } + + @Test + public void testStoreSubscribedEventTypesDBError() throws SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeBatch()).thenThrow(new SQLException()); + List sampleEventTypes = EventNotificationTestUtils.getSampleStoredEventTypes(); + + Assert.assertThrows(OBEventNotificationException.class, () -> eventSubscriptionDAOImpl. + storeSubscribedEventTypes(mockedConnection, EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + sampleEventTypes)); + } + + @Test + public void testGetEventSubscriptionBySubscriptionId() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.next()).thenReturn(true, true, true, false); + when(mockedResultSet.getString(EventNotificationConstants.EVENT_TYPE)). + thenReturn(EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2); + + EventSubscription result = eventSubscriptionDAOImpl.getEventSubscriptionBySubscriptionId( + mockedConnection, EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + List eventTypes = result.getEventTypes(); + Assert.assertTrue(eventTypes.contains(EventNotificationTestConstants. + SAMPLE_NOTIFICATION_EVENT_TYPE_1)); + } + + @Test + public void testGetEventSubscriptionBySubscriptionIdNotFound() throws SQLException { + when(mockedConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.next()).thenReturn(false); + + Assert.assertThrows(OBEventNotificationException.class, () -> eventSubscriptionDAOImpl. + getEventSubscriptionBySubscriptionId(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1)); + } + + @Test + public void testGetEventSubscriptionBySubscriptionIdDBError() throws SQLException { + when(mockedConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeQuery()).thenThrow(new SQLException()); + + Assert.assertThrows(OBEventNotificationException.class, () -> eventSubscriptionDAOImpl. + getEventSubscriptionBySubscriptionId(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1)); + } + + @Test + public void testGetEventSubscriptionsByClientId() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.isBeforeFirst()).thenReturn(true); + when(mockedResultSet.next()).thenReturn(true, true, true, true, true, true, true, false); + when(mockedResultSet.getString(EventNotificationConstants.SUBSCRIPTION_ID)). + thenReturn(EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2); + when(mockedResultSet.getString(EventNotificationConstants.EVENT_TYPE)). + thenReturn(EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2); + + List eventSubscriptions = eventSubscriptionDAOImpl.getEventSubscriptionsByClientId( + mockedConnection, EventNotificationTestConstants.SAMPLE_CLIENT_ID); + + Assert.assertNotNull(eventSubscriptions); + Assert.assertEquals(2, eventSubscriptions.size()); // We expect one EventSubscription object + + EventSubscription subscription = eventSubscriptions.get(0); + Assert.assertNotNull(subscription.getEventTypes()); + Assert.assertEquals(subscription.getEventTypes().size(), 2); + Assert.assertTrue(subscription.getEventTypes().contains(EventNotificationTestConstants. + SAMPLE_NOTIFICATION_EVENT_TYPE_1)); + Assert.assertTrue(subscription.getEventTypes().contains(EventNotificationTestConstants. + SAMPLE_NOTIFICATION_EVENT_TYPE_2)); + + EventSubscription subscription2 = eventSubscriptions.get(1); + Assert.assertNotNull(subscription2.getEventTypes()); + Assert.assertEquals(subscription2.getEventTypes().size(), 2); + Assert.assertTrue(subscription2.getEventTypes().contains(EventNotificationTestConstants. + SAMPLE_NOTIFICATION_EVENT_TYPE_1)); + Assert.assertTrue(subscription2.getEventTypes().contains(EventNotificationTestConstants. + SAMPLE_NOTIFICATION_EVENT_TYPE_2)); + } + + @Test + public void testGetEventSubscriptionsByClientIdNoSubscriptions() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.isBeforeFirst()).thenReturn(false); + + List eventSubscriptions = eventSubscriptionDAOImpl.getEventSubscriptionsByClientId( + mockedConnection, EventNotificationTestConstants.SAMPLE_CLIENT_ID); + + Assert.assertNotNull(eventSubscriptions); + Assert.assertTrue(eventSubscriptions.isEmpty()); // We expect an empty list since no data was found + } + + @Test + public void testGetEventSubscriptionsByEventType() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.isBeforeFirst()).thenReturn(true); + when(mockedResultSet.next()).thenReturn(true, true, true, true, true, true, true, false); + when(mockedResultSet.getString(EventNotificationConstants.SUBSCRIPTION_ID)). + thenReturn(EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2); + when(mockedResultSet.getString(EventNotificationConstants.EVENT_TYPE)). + thenReturn(EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_2); + + List eventSubscriptions = eventSubscriptionDAOImpl. + getEventSubscriptionsByEventType(mockedConnection, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1); + + Assert.assertEquals(2, eventSubscriptions.size()); + + EventSubscription subscription1 = eventSubscriptions.get(0); + Assert.assertEquals(EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1, subscription1.getSubscriptionId()); + Assert.assertEquals(subscription1.getEventTypes().size(), 2); + Assert.assertEquals(EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + subscription1.getEventTypes().get(0)); + + EventSubscription subscription2 = eventSubscriptions.get(1); + Assert.assertEquals(EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_2, subscription2.getSubscriptionId()); + Assert.assertEquals(subscription2.getEventTypes().size(), 2); + Assert.assertEquals(EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1, + subscription2.getEventTypes().get(0)); + } + + @Test + public void testGetEventSubscriptionsByEventTypeNoSubscriptions() throws OBEventNotificationException, + SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.isBeforeFirst()).thenReturn(false); + + List eventSubscriptions = eventSubscriptionDAOImpl. + getEventSubscriptionsByEventType(mockedConnection, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1); + + Assert.assertEquals(0, eventSubscriptions.size()); + } + + @Test(expectedExceptions = OBEventNotificationException.class) + public void testGetEventSubscriptionsByEventType_SQLException() throws OBEventNotificationException, + SQLException { + // Mock the behavior of the PreparedStatement and ResultSet + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + ResultSet mockedResultSet = Mockito.mock(ResultSet.class); + when(mockedPreparedStatement.executeQuery()).thenReturn(mockedResultSet); + when(mockedResultSet.isBeforeFirst()).thenThrow(new SQLException()); + + // Call the method under test (expecting an exception to be thrown) + eventSubscriptionDAOImpl.getEventSubscriptionsByEventType(mockedConnection, + EventNotificationTestConstants.SAMPLE_NOTIFICATION_EVENT_TYPE_1); + } + + @Test + public void testUpdateEventSubscription() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(1); + + Boolean isUpdated = eventSubscriptionDAOImpl.updateEventSubscription(mockedConnection, + EventNotificationTestUtils.getSampleEventSubscriptionToBeUpdated()); + Assert.assertTrue(isUpdated); + } + + @Test + public void testUpdateEventSubscriptionFailed() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(0); + + Boolean isUpdated = eventSubscriptionDAOImpl.updateEventSubscription(mockedConnection, + EventNotificationTestUtils.getSampleEventSubscriptionToBeUpdated()); + Assert.assertFalse(isUpdated); + } + + @Test + public void testUpdateEventSubscriptionDBError() throws SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenThrow(new SQLException()); + + Assert.assertThrows(OBEventNotificationException.class, + () -> eventSubscriptionDAOImpl.updateEventSubscription(mockedConnection, + EventNotificationTestUtils.getSampleEventSubscriptionToBeUpdated())); + } + + @Test + public void testDeleteEventSubscription() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(1); + + Boolean isDeleted = eventSubscriptionDAOImpl.deleteEventSubscription(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + + Assert.assertTrue(isDeleted); + } + + @Test + public void testDeleteEventSubscriptionFails() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(0); + + Boolean isDeleted = eventSubscriptionDAOImpl.deleteEventSubscription(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + + Assert.assertFalse(isDeleted); + } + + @Test(expectedExceptions = OBEventNotificationException.class) + public void testDeleteEventSubscriptionDBError() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenThrow(new SQLException()); + + eventSubscriptionDAOImpl.deleteEventSubscription(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + } + + @Test + public void testDeleteSubscribedEventTypes() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(1); + + boolean isDeleted = eventSubscriptionDAOImpl.deleteSubscribedEventTypes(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + + Assert.assertTrue(isDeleted); + } + + @Test + public void testDeleteSubscribedEventTypesFails() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenReturn(0); + + boolean isDeleted = eventSubscriptionDAOImpl.deleteSubscribedEventTypes(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + + Assert.assertFalse(isDeleted); + } + + @Test(expectedExceptions = OBEventNotificationException.class) + public void testDeleteSubscribedEventTypesDBError() throws OBEventNotificationException, SQLException { + when(mockedConnection.prepareStatement(anyString())).thenReturn(mockedPreparedStatement); + when(mockedPreparedStatement.executeUpdate()).thenThrow(new SQLException()); + + eventSubscriptionDAOImpl.deleteSubscribedEventTypes(mockedConnection, + EventNotificationTestConstants.SAMPLE_SUBSCRIPTION_ID_1); + } +} + diff --git a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/resources/testng.xml b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/resources/testng.xml index 01b9ba0a..783c7d6a 100644 --- a/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/resources/testng.xml +++ b/open-banking-accelerator/components/event-notifications/com.wso2.openbanking.accelerator.event.notifications.service/src/test/resources/testng.xml @@ -1,5 +1,5 @@ - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -34,7 +32,7 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-accelerator/components/ob-throttler/com.wso2.openbanking.accelerator.throttler.service/pom.xml b/open-banking-accelerator/components/ob-throttler/com.wso2.openbanking.accelerator.throttler.service/pom.xml index db7c0224..4dce7220 100644 --- a/open-banking-accelerator/components/ob-throttler/com.wso2.openbanking.accelerator.throttler.service/pom.xml +++ b/open-banking-accelerator/components/ob-throttler/com.wso2.openbanking.accelerator.throttler.service/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -34,12 +32,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.throttler.dao provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.application.info.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.application.info.endpoint/pom.xml index 6af5d071..760f2e03 100755 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.application.info.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.application.info.endpoint/pom.xml @@ -17,13 +17,11 @@ ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -64,12 +62,12 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.ciba.authentication.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.ciba.authentication.endpoint/pom.xml index d4fd068c..f90da6fb 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.ciba.authentication.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.ciba.authentication.endpoint/pom.xml @@ -17,8 +17,8 @@ --> open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -35,7 +35,7 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions provided @@ -45,7 +45,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.consent.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.consent.endpoint/pom.xml index 6a9e406d..6c08ef40 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.consent.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.consent.endpoint/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml @@ -63,7 +61,7 @@ test - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -74,7 +72,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao @@ -85,7 +83,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service @@ -107,7 +105,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml index ceabea67..6eb99a78 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/pom.xml @@ -16,13 +16,11 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -67,7 +65,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -78,7 +76,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -185,8 +183,8 @@ true true ${project.basedir}/src/main/resources/dynamic.client.registration.yaml - jaxrs-cxf + jaxrs-cxf src/gen/java true diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/api/ClientRegistrationApiImpl.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/api/ClientRegistrationApiImpl.java index ad6eeb14..e7e37a9a 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/api/ClientRegistrationApiImpl.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/api/ClientRegistrationApiImpl.java @@ -15,10 +15,12 @@ * specific language governing permissions and limitations * under the License. */ + package com.wso2.openbanking.accelerator.identity.dcr.endpoint.impl.api; import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; import com.wso2.openbanking.accelerator.common.util.JWTUtils; import com.wso2.openbanking.accelerator.identity.dcr.endpoint.impl.RegistrationConstants; import com.wso2.openbanking.accelerator.identity.dcr.endpoint.impl.service.RegistrationServiceHandler; @@ -173,19 +175,16 @@ public Response registerClientIdPut(@Context HttpServletRequest request, @Contex Map requestAttributes = (Map) gson.fromJson(registrationRequestDetails, Map.class); - //decode SSA - if (registrationRequest.getSoftwareStatement() == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(RegistrationUtils - .getErrorDTO(DCRCommonConstants.INVALID_META_DATA, - "Required parameter software statement cannot be null")) - .build(); - } - String ssaBody = JWTUtils.decodeRequestJWT(registrationRequest.getSoftwareStatement(), "body") - .toString(); - Map ssaAttributesMap = gson.fromJson(ssaBody, Map.class); - //RegistrationRequest registrationRequest = RegistrationUtils.getRegistrationRequest(requestAttributeMap); registrationRequest.setRequestParameters(requestAttributes); - registrationRequest.setSsaParameters(ssaAttributesMap); + + if (StringUtils.isNotEmpty(registrationRequest.getSoftwareStatement())) { + //decode SSA if provided in the registration request + String ssaBody = JWTUtils.decodeRequestJWT(registrationRequest.getSoftwareStatement(), + OpenBankingConstants.JWT_BODY) + .toString(); + Map ssaAttributesMap = gson.fromJson(ssaBody, Map.class); + registrationRequest.setSsaParameters(ssaAttributesMap); + } String clientId = uriInfo.getPathParameters().getFirst("s"); RegistrationUtils.validateRegistrationCreation(registrationRequest); @@ -265,19 +264,16 @@ public Response registerPost(@Context HttpServletRequest request, @Context HttpS log.error("Certificate not valid", e); } - //decode SSA - if (StringUtils.isBlank(registrationRequest.getSoftwareStatement())) { - return Response.status(Response.Status.BAD_REQUEST).entity(RegistrationUtils - .getErrorDTO(DCRCommonConstants.INVALID_META_DATA, - "Required parameter software statement cannot be null")) - .build(); + registrationRequest.setRequestParameters(requestAttributes); + if (StringUtils.isNotEmpty(registrationRequest.getSoftwareStatement())) { + //decode SSA if provided in the registration request + String ssaBody = JWTUtils.decodeRequestJWT(registrationRequest.getSoftwareStatement(), + OpenBankingConstants.JWT_BODY) + .toString(); + Map ssaAttributesMap = gson.fromJson(ssaBody, Map.class); + registrationRequest.setSsaParameters(ssaAttributesMap); } - String ssaBody = JWTUtils.decodeRequestJWT(registrationRequest.getSoftwareStatement(), "body") - .toString(); - Map ssaAttributesMap = gson.fromJson(ssaBody, Map.class); - registrationRequest.setRequestParameters(requestAttributes); - registrationRequest.setSsaParameters(ssaAttributesMap); RegistrationUtils.validateRegistrationCreation(registrationRequest); //do specific validations registrationValidator.validatePost(registrationRequest); @@ -288,7 +284,7 @@ public Response registerPost(@Context HttpServletRequest request, @Context HttpS log.error("Error occurred while creating the Service provider", e); if (DCRCommonConstants.DUPLICATE_APPLICATION_NAME.equalsIgnoreCase(e.getErrorCode())) { return Response.status(Response.Status.BAD_REQUEST).entity(RegistrationUtils - .getErrorDTO(DCRCommonConstants.INVALID_META_DATA, e.getErrorDescription())) + .getErrorDTO(DCRCommonConstants.INVALID_META_DATA, e.getErrorDescription())) .build(); } } catch (IdentityApplicationManagementException e) { @@ -296,7 +292,7 @@ public Response registerPost(@Context HttpServletRequest request, @Context HttpS } catch (DCRValidationException e) { log.error("Error occurred while validating request", e); return Response.status(Response.Status.BAD_REQUEST).entity(RegistrationUtils - .getErrorDTO(e.getErrorCode(), e.getErrorDescription())) + .getErrorDTO(e.getErrorCode(), e.getErrorDescription())) .build(); } catch (net.minidev.json.parser.ParseException | IOException e) { log.error("Error occurred while parsing the request", e); diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/service/RegistrationServiceHandler.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/service/RegistrationServiceHandler.java index 8aa4a4ed..6fdaa3f4 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/service/RegistrationServiceHandler.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/service/RegistrationServiceHandler.java @@ -25,7 +25,6 @@ import com.wso2.openbanking.accelerator.identity.dcr.model.RegistrationRequest; import com.wso2.openbanking.accelerator.identity.dcr.validation.DCRCommonConstants; import com.wso2.openbanking.accelerator.identity.dcr.validation.RegistrationValidator; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.PrivilegedCarbonContext; @@ -75,8 +74,9 @@ public Response createRegistration(RegistrationRequest registrationRequest, .get(OpenBankingConstants.DCR_JWKS_NAME).toString(); } } + String applicationName = RegistrationUtils.getApplicationName(registrationRequest, useSoftwareIdAsAppName); Application application = dcrmService.registerApplication(RegistrationUtils - .getApplicationRegistrationRequest(registrationRequest, useSoftwareIdAsAppName)); + .getApplicationRegistrationRequest(registrationRequest, applicationName)); if (log.isDebugEnabled()) { log.debug("Created application with name :" + application.getClientName()); } @@ -84,11 +84,9 @@ public Response createRegistration(RegistrationRequest registrationRequest, ServiceProvider serviceProvider = applicationManagementService .getServiceProvider(application.getClientName(), tenantDomain); - if (StringUtils.isNotEmpty(jwksEndpointName)) { - serviceProvider.setJwksUri(registrationRequest.getSsaParameters().get(jwksEndpointName).toString()); - } else { - serviceProvider.setJwksUri(registrationRequest.getSoftwareStatementBody().getJwksURI()); - } + //get JWKS URI from the request + String jwksUri = RegistrationUtils.getJwksUriFromRequest(registrationRequest, jwksEndpointName); + serviceProvider.setJwksUri(jwksUri); Long clientIdIssuedTime = Instant.now().getEpochSecond(); //store the client details as SP meta data @@ -108,11 +106,12 @@ public Response createRegistration(RegistrationRequest registrationRequest, Map registrationData = registrationRequest.getRequestParameters(); registrationData.put(RegistrationConstants.CLIENT_ID, application.getClientId()); registrationData.put(RegistrationConstants.CLIENT_ID_ISSUED_AT, clientIdIssuedTime.toString()); - registrationData.putAll(registrationRequest.getSsaParameters()); + if (registrationRequest.getSsaParameters() != null) { + registrationData.putAll(registrationRequest.getSsaParameters()); + } registrationData.putAll(additionalAttributes); String registrationResponse = registrationValidator.getRegistrationResponse(registrationData); return Response.status(Response.Status.CREATED).entity(registrationResponse).build(); - } public Response retrieveRegistration(Map additionalAttributes, String clientId, String accessToken) @@ -164,17 +163,20 @@ public Response updateRegistration(RegistrationRequest request, Map updateRequestData = RegistrationUtils.getAlteredApplicationAttributes(request); Map updateRegistrationData = request.getRequestParameters(); - updateRegistrationData.putAll(request.getSsaParameters()); + if (request.getSsaParameters() != null) { + updateRegistrationData.putAll(request.getSsaParameters()); + } updateRequestData.put(RegistrationConstants.CLIENT_ID_ISSUED_AT, clientIdIssuedAt); // Adding SP property to identify update request. Will be removed when updating authenticators. updateRequestData.put("AppCreateRequest", "false"); diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/RegistrationUtils.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/RegistrationUtils.java index fbb3749c..eef4a113 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/RegistrationUtils.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/RegistrationUtils.java @@ -18,7 +18,6 @@ package com.wso2.openbanking.accelerator.identity.dcr.endpoint.impl.util; import com.google.gson.Gson; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.wso2.openbanking.accelerator.common.util.JWTUtils; @@ -76,8 +75,9 @@ public static void validateRegistrationCreation(RegistrationRequest registration RegistrationValidator dcrRequestValidator; dcrRequestValidator = RegistrationValidator.getRegistrationValidator(); - // set the ssa payload according to the specification format + if (StringUtils.isNotEmpty(registrationRequest.getSoftwareStatement())) { + // set the ssa payload according to the specification format String decodedSSA = JWTUtils .decodeRequestJWT(registrationRequest.getSoftwareStatement(), "body").toJSONString(); dcrRequestValidator.setSoftwareStatementPayload(registrationRequest, decodedSSA); @@ -105,41 +105,71 @@ public static RegistrationError getRegistrationError(String errorCode, String er } public static ApplicationRegistrationRequest getApplicationRegistrationRequest( - RegistrationRequest registrationRequest, boolean useSoftwareIdAsAppName) { + RegistrationRequest registrationRequest, String applicationName) { - String applicationName = ""; - if (useSoftwareIdAsAppName) { - applicationName = registrationRequest.getSoftwareStatementBody().getSoftwareId(); - } else { - applicationName = RegistrationUtils.getSafeApplicationName( - registrationRequest.getSoftwareStatementBody().getClientName()); - } ApplicationRegistrationRequest appRegistrationRequest = new ApplicationRegistrationRequest(); appRegistrationRequest.setClientName(applicationName); - appRegistrationRequest.setRedirectUris(registrationRequest.getSoftwareStatementBody().getCallbackUris()); appRegistrationRequest.setGrantTypes(registrationRequest.getGrantTypes()); - return appRegistrationRequest; + // Get the redirect URIs based on the presence of software statement + List redirectUris = StringUtils.isEmpty(registrationRequest.getSoftwareStatement()) + ? registrationRequest.getCallbackUris() + : registrationRequest.getSoftwareStatementBody().getCallbackUris(); + appRegistrationRequest.setRedirectUris(redirectUris); + + return appRegistrationRequest; } public static ApplicationUpdateRequest getApplicationUpdateRequest(RegistrationRequest registrationRequest, - boolean useSoftwareIdAsAppName) { + String applicationName) { - String applicationName = ""; - if (useSoftwareIdAsAppName) { - applicationName = registrationRequest.getSoftwareStatementBody().getSoftwareId(); - } else { - applicationName = RegistrationUtils.getSafeApplicationName( - registrationRequest.getSoftwareStatementBody().getClientName()); - } ApplicationUpdateRequest applicationUpdateRequest = new ApplicationUpdateRequest(); applicationUpdateRequest.setClientName(applicationName); - applicationUpdateRequest.setRedirectUris(registrationRequest.getSoftwareStatementBody().getCallbackUris()); applicationUpdateRequest.setGrantTypes(registrationRequest.getGrantTypes()); + // Get the redirect URIs based on the presence of software statement + List redirectUris = StringUtils.isEmpty(registrationRequest.getSoftwareStatement()) + ? registrationRequest.getCallbackUris() + : registrationRequest.getSoftwareStatementBody().getCallbackUris(); + + applicationUpdateRequest.setRedirectUris(redirectUris); + return applicationUpdateRequest; + } + /** + * Retrieves the application name from the registration request. + * + * @param request registration or update request + * @param useSoftwareIdAsAppName Indicates whether to use the software ID as the application name + * @return The application name + */ + public static String getApplicationName(RegistrationRequest request, boolean useSoftwareIdAsAppName) { + if (useSoftwareIdAsAppName) { + // If the request does not contain a software statement, get the software Id directly from the request + if (StringUtils.isEmpty(request.getSoftwareStatement())) { + return request.getSoftwareId(); + } + return request.getSoftwareStatementBody().getSoftwareId(); + } + return RegistrationUtils.getSafeApplicationName(request.getSoftwareStatementBody().getClientName()); + } + /** + * Retrieves the JWKS URI from the registration request based on the presence of the software statement. + * + * @param registrationRequest registration or update request + * @param jwksEndpointName name used for the JWKS endpoint in the software statement + * @return JWKS URI. + */ + public static String getJwksUriFromRequest(RegistrationRequest registrationRequest, String jwksEndpointName) { + if (StringUtils.isEmpty(registrationRequest.getSoftwareStatement())) { + return registrationRequest.getJwksURI(); + } + if (StringUtils.isNotEmpty(jwksEndpointName)) { + return registrationRequest.getSsaParameters().get(jwksEndpointName).toString(); + } + return registrationRequest.getSoftwareStatementBody().getJwksURI(); } public static ArrayList getServiceProviderPropertyList @@ -167,7 +197,7 @@ public static Map getSpMetaDataMap(List for (ServiceProviderProperty spProperty : spPropertyList) { if (spProperty.getValue().contains(DCRCommonConstants.ARRAY_ELEMENT_SEPERATOR)) { List metaDataList = Stream.of(spProperty.getValue() - .split(DCRCommonConstants.ARRAY_ELEMENT_SEPERATOR)) + .split(DCRCommonConstants.ARRAY_ELEMENT_SEPERATOR)) .map(String::trim) .collect(Collectors.toList()); getJsonElementListFromString(metaDataList); @@ -196,23 +226,17 @@ public static String getSafeApplicationName(String applicationName) { } - public static Map getAlteredApplicationAttributes(RegistrationRequest registrationRequest) - throws ParseException { + public static Map getAlteredApplicationAttributes(RegistrationRequest registrationRequest) { Map alteredAppAttributeMap = new HashMap<>(); - JsonElement registrationRequestDetails = gson.toJsonTree(registrationRequest); - Map appAttributeMap = (Map) - gson.fromJson(registrationRequestDetails, Map.class); - appAttributeMap.remove("softwareStatementBody"); - appAttributeMap.remove("requestParameters"); - appAttributeMap.remove("ssaParameters"); - addAttributes(appAttributeMap, alteredAppAttributeMap); - //add ssa attributes - - addAttributes(registrationRequest.getSsaParameters(), alteredAppAttributeMap); + addAttributes(registrationRequest.getRequestParameters(), alteredAppAttributeMap); - //add ssa issuer - alteredAppAttributeMap.put("ssaIssuer", registrationRequest.getSsaParameters().get("iss").toString()); + if (StringUtils.isNotEmpty(registrationRequest.getSoftwareStatement())) { + //add ssa attributes + addAttributes(registrationRequest.getSsaParameters(), alteredAppAttributeMap); + //add ssa issuer + alteredAppAttributeMap.put("ssaIssuer", registrationRequest.getSsaParameters().get("iss").toString()); + } return alteredAppAttributeMap; } @@ -249,7 +273,11 @@ public static void addAttributes(Map requestAttributes, alteredAttributes.put(entry.getKey().toString(), gson.toJson(entry.getValue())); } else { //remove unnecessary inverted commas. - alteredAttributes.put(entry.getKey().toString(), entry.getValue().toString()); + if (entry.getValue() != null) { + // This is to handle optional nullable params. + // Ex: "software_on_behalf_of_org":null + alteredAttributes.put(entry.getKey().toString(), entry.getValue().toString()); + } } } } diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/ResponseStatus.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/ResponseStatus.java index 6e02b6ee..ab002635 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/ResponseStatus.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.dcr.endpoint/src/main/java/com/wso2/openbanking/accelerator/identity/dcr/endpoint/impl/util/ResponseStatus.java @@ -24,182 +24,157 @@ public enum ResponseStatus { /** - * 200 OK, see {@link - * HTTP/1.1 documentation}. + * 200 OK, see .... */ OK(200, "OK"), /** - * 201 Created, see {@link - * HTTP/1.1 documentation}. + * 201 Created, see .... */ CREATED(201, "Created"), /** - * 202 Accepted, see {@link - * HTTP/1.1 documentation}. + * 202 Accepted, see .... */ ACCEPTED(202, "Accepted"), /** - * 204 No Content, see {@link - * HTTP/1.1 documentation}. + * 204 No Content, see .... */ NO_CONTENT(204, "No Content"), /** - * 205 Reset Content, see {@link - * HTTP/1.1 documentation}. + * 205 Reset Content, see .... * * @since 2.0 */ RESET_CONTENT(205, "Reset Content"), /** - * 206 Reset Content, see {@link - * HTTP/1.1 documentation}. + * 206 Reset Content, see .... * * @since 2.0 */ PARTIAL_CONTENT(206, "Partial Content"), /** - * 301 Moved Permanently, see {@link - * HTTP/1.1 documentation}. + * 301 Moved Permanently, + * see .... */ MOVED_PERMANENTLY(301, "Moved Permanently"), /** - * 302 Found, see {@link - * HTTP/1.1 documentation}. + * 302 Found, see .... * * @since 2.0 */ FOUND(302, "Found"), /** - * 303 See Other, see {@link - * HTTP/1.1 documentation}. + * 303 See Other, see .... */ SEE_OTHER(303, "See Other"), /** - * 304 Not Modified, see {@link - * HTTP/1.1 documentation}. + * 304 Not Modified, see .... */ NOT_MODIFIED(304, "Not Modified"), /** - * 305 Use Proxy, see {@link - * HTTP/1.1 documentation}. + * 305 Use Proxy, see .... * * @since 2.0 */ USE_PROXY(305, "Use Proxy"), /** - * 307 Temporary Redirect, see {@link - * HTTP/1.1 documentation}. + * 307 Temporary Redirect, see .... */ TEMPORARY_REDIRECT(307, "Temporary Redirect"), /** - * 400 Bad Request, see {@link - * HTTP/1.1 documentation}. + * 400 Bad Request, see .... */ BAD_REQUEST(400, "Bad Request"), /** - * 401 Unauthorized, see {@link - * HTTP/1.1 documentation}. + * 401 Unauthorized, see .... */ UNAUTHORIZED(401, "Unauthorized"), /** - * 402 Payment Required, see {@link - * HTTP/1.1 documentation}. + * 402 Payment Required, see .... * * @since 2.0 */ PAYMENT_REQUIRED(402, "Payment Required"), /** - * 403 Forbidden, see {@link - * HTTP/1.1 documentation}. + * 403 Forbidden, see .... */ FORBIDDEN(403, "Forbidden"), /** - * 404 Not Found, see {@link - * HTTP/1.1 documentation}. + * 404 Not Found, see .... */ NOT_FOUND(404, "Not Found"), /** - * 405 Method Not Allowed, see {@link - * HTTP/1.1 documentation}. + * 405 Method Not Allowed, see .... * * @since 2.0 */ METHOD_NOT_ALLOWED(405, "Method Not Allowed"), /** - * 406 Not Acceptable, see {@link - * HTTP/1.1 documentation}. + * 406 Not Acceptable, see .... */ NOT_ACCEPTABLE(406, "Not Acceptable"), /** - * 409 Conflict, see {@link - * HTTP/1.1 documentation}. + * 409 Conflict, see .... */ CONFLICT(409, "Conflict"), /** - * 410 Gone, see {@link - * HTTP/1.1 documentation}. + * 410 Gone, see .... */ GONE(410, "Gone"), /** - * 411 Length Required, see {@link - * HTTP/1.1 documentation}. + * 411 Length Required, see .... * * @since 2.0 */ LENGTH_REQUIRED(411, "Length Required"), /** - * 412 Precondition Failed, see {@link - * HTTP/1.1 documentation}. + * 412 Precondition Failed, see .... */ PRECONDITION_FAILED(412, "Precondition Failed"), /** - * 413 Request Entity Too Large, see {@link HTTP/1.1 documentation}. + * 413 Request Entity Too Large, see HTTP/1.1 documentation. * * @since 2.0 */ REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"), /** - * 414 Request-URI Too Long, see {@link - * HTTP/1.1 documentation}. + * 414 Request-URI Too Long, + * see .... * * @since 2.0 */ REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"), /** - * 415 Unsupported Media Type, see {@link HTTP/1.1 documentation}. + * 415 Unsupported Media Type, see HTTP/1.1 documentation. */ UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), /** - * 416 Requested Range Not Satisfiable, see {@link HTTP/1.1 documentation}. + * 416 Requested Range Not Satisfiable, see HTTP/1.1 documentation. * * @since 2.0 */ REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested Range Not Satisfiable"), /** - * 417 Expectation Failed, see {@link - * HTTP/1.1 documentation}. + * 417 Expectation Failed, see .... * * @since 2.0 */ EXPECTATION_FAILED(417, "Expectation Failed"), /** - * 500 Internal Server Error, see {@link - * HTTP/1.1 documentation}. + * 500 Internal Server Error, + * see .... */ INTERNAL_SERVER_ERROR(500, "Internal Server Error"), /** - * 501 Not Implemented, see {@link - * HTTP/1.1 documentation}. + * 501 Not Implemented, see .... * * @since 2.0 */ NOT_IMPLEMENTED(501, "Not Implemented"), /** - * 503 Service Unavailable, see {@link - * HTTP/1.1 documentation}. + * 503 Service Unavailable, see .... */ SERVICE_UNAVAILABLE(503, "Service Unavailable"); diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/pom.xml index 89ba7125..c5cae4ff 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/pom.xml @@ -17,13 +17,11 @@ ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -43,7 +41,7 @@ ${spotbugs.annotations.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/java/com/wso2/openbanking/accelerator/demo/backend/services/VrpService.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/java/com/wso2/openbanking/accelerator/demo/backend/services/VrpService.java new file mode 100644 index 00000000..14ce852c --- /dev/null +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/java/com/wso2/openbanking/accelerator/demo/backend/services/VrpService.java @@ -0,0 +1,290 @@ +/** + * 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 com.wso2.openbanking.accelerator.demo.backend.services; + +import com.wso2.openbanking.accelerator.common.config.OpenBankingConfigParser; +import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants; +import com.wso2.openbanking.accelerator.demo.backend.BankException; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Random; +import java.util.UUID; + + +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + + +/** + * Vrp Service class. + */ +@Path("/vrpservice/") +public class VrpService { + + public static final String EXPECTED_EXECUTION_TIME = "ExpectedExecutionDateTime"; + public static final String EXPECTED_SETTLEMENT_TIME = "ExpectedSettlementDateTime"; + private static final int MAX_LIMIT = 500; + private static final Queue domesticVRPsIdQueue = new LinkedList<>(); + private static final Map domesticVRPs = new HashMap<>(); + + + @SuppressFBWarnings("JAXRS_ENDPOINT") + // Suppressed content - Endpoint + // Suppression reason - False Positive : This endpoint is a demo endpoint that is not exposed in production + // Suppressed warning count - 1 + @GET + @Path("/domestic-vrp-consents/{ConsentId}/funds-confirmation") + @Produces("application/json; charset=utf-8") + public Response getPaymentTypeFundsConfirmation(@PathParam("ConsentId") String domesticVRPId) { + + Instant currentDate = Instant.now(); + + String response = "{\n" + + " \"Data\": {\n" + + " \"FundsAvailableResult\": {\n" + + " \"FundsAvailableDateTime\": \"" + currentDate.toString() + "\",\n" + + " \"FundsAvailable\": true\n" + + " }\n" + + " },\n" + + " \"Links\": {\n" + + " \"Self\": \"/vrp/domestic-vrps/" + domesticVRPId + "/funds-confirmation\"\n" + + " },\n" + + " \"Meta\": {}\n" + + "}"; + + return Response.status(200).entity(response) + .header("x-fapi-interaction-id", UUID.randomUUID().toString()) + .build(); + } + + @SuppressFBWarnings("JAXRS_ENDPOINT") + // Suppressed content - Endpoint + // Suppression reason - False Positive : This endpoint is a demo endpoint that is not exposed in production + // Suppressed warning count - 1 + + @POST + @Path("/domestic-vrps") + @Produces("application/json; charset=utf-8") + public Response paymentSubmission(String requestString, @PathParam("paymentType") String paymentType, + @HeaderParam("x-fapi-interaction-id") String fid, + @HeaderParam("Account-Request-Information") String accountRequestInfo) + throws BankException { + + JSONObject jsonObject; + JSONObject accountRequestInformation; + + try { + accountRequestInformation = getRequest(paymentType, accountRequestInfo); + JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + jsonObject = (JSONObject) parser.parse(requestString); + } catch (ParseException e) { + throw new BankException("Error in casting JSON body " + e); + } + + JSONObject additionalConsentInfo = (JSONObject) accountRequestInformation.get("additionalConsentInfo"); + + JSONObject response = cacheAndGetPaymentResponse(paymentType, jsonObject, additionalConsentInfo); + return Response.status(201).entity(response.toString()) + .header("x-fapi-interaction-id", fid) + .build(); + + } + + @SuppressFBWarnings("JAXRS_ENDPOINT") + // Suppressed content - Endpoint + // Suppression reason - False Positive : This endpoint is a demo endpoint that is not exposed in production + // Suppressed warning count - 1 + + @GET + @Path("/domestic-vrps/{domesticVRPId}") + @Produces("application/json; charset=utf-8") + public Response getPaymentTypePayment(@PathParam("domesticVRPId") String domesticVRPId) { + + JSONObject responseObject = null; + if (StringUtils.isNotBlank(domesticVRPId)) { + + responseObject = domesticVRPs.get(domesticVRPId); + + } + if (responseObject == null) { + responseObject = new JSONObject(); + } + + + return Response.status(200).entity(responseObject.toString()) + .header("x-fapi-interaction-id", "93bac548-d2de-4546-b106-880a5018460d") + .build(); + } + + + private static JSONObject getRequest(String paymentType, String json) throws ParseException { + + String[] splitString = json.split("\\."); + String base64EncodedBody = splitString[1]; + String decodedString = null; + decodedString = new String(Base64.getUrlDecoder() + .decode(base64EncodedBody.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + + JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + JSONObject jsonObject = (JSONObject) parser.parse(decodedString); + return jsonObject; + } + + + @SuppressFBWarnings("PREDICTABLE_RANDOM") + // Suppressed content - PREDICTABLE_RANDOM + // Suppression reason - False Positive : This endpoint is a demo endpoint that is not exposed in production + // Suppressed warning count - 1 + private JSONObject cacheAndGetPaymentResponse(String paymentType, JSONObject requestObject, + JSONObject additionalConsentInfo) + throws BankException { + + JSONObject responseObject; + + int randomPIN = new Random().nextInt(100); + + String status; + String paymentIdValue; + + paymentIdValue = ((JSONObject) requestObject.get("Data")).getAsString("ConsentId"); + paymentIdValue = paymentIdValue + "-" + randomPIN; + + status = "AcceptedSettlementCompleted"; + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); + Date date = new Date(); + String currentDate = dateFormat.format(date); + + String readRefundAccount = additionalConsentInfo.getAsString("ReadRefundAccount"); + String cutOffTimeAcceptable = additionalConsentInfo.getAsString("CutOffTimeAcceptable"); + + try { + JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE); + responseObject = (JSONObject) parser.parse(requestObject.toString()); + + JSONObject dataObject = (JSONObject) responseObject.get("Data"); + + dataObject.put("DomesticVRPId", paymentIdValue); + dataObject.put("Status", status); + dataObject.put("CreationDateTime", currentDate); + dataObject.put("StatusUpdateDateTime", currentDate); + + if ("domestic-vrps".equals(paymentType)) { + JSONObject debtorAccount = new JSONObject(); + debtorAccount.put("SchemeName", "SortCodeAccountNumber"); + debtorAccount.put("SecondaryIdentification", "Roll 2901"); + debtorAccount.put("Name", "Deb Mal"); + debtorAccount.put("Identification", additionalConsentInfo.getAsString("AccountIds") + .split(":")[0].replace("[\"", "")); + + dataObject.put("DebtorAccount", debtorAccount); + + } + + // Add refund account details if requested during consent initiation + if (Boolean.parseBoolean(readRefundAccount)) { + addRefundAccount(dataObject); + } + + if (Boolean.parseBoolean(cutOffTimeAcceptable)) { + dataObject.put(EXPECTED_EXECUTION_TIME, constructDateTime(1L, + OpenBankingConstants.EXPECTED_EXECUTION_TIME)); + dataObject.put(EXPECTED_SETTLEMENT_TIME, constructDateTime(1L, + OpenBankingConstants.EXPECTED_SETTLEMENT_TIME)); + } + + JSONObject linksObject = new JSONObject(); + linksObject.put("Self", "/domestic-vrps/" + paymentIdValue); + responseObject.put("Links", linksObject); + + JSONObject metaObject = new JSONObject(); + responseObject.put("Meta", metaObject); + + } catch (ParseException e) { + throw new BankException(e); + } + addToCache(paymentIdValue, responseObject); + return responseObject; + } + + /** + * Add Refund account details to the response. + * + * @param dataObject + */ + private void addRefundAccount(JSONObject dataObject) { + + String schemeName = "OB.SortCodeAccountNumber"; + String identification = "Identification"; + String name = "NTPC Inc"; + + JSONObject accountData = new JSONObject(); + accountData.put("SchemeName", schemeName); + accountData.put("Identification", identification); + accountData.put("Name", name); + + JSONObject account = new JSONObject(); + account.put("Account", accountData); + + dataObject.put("Refund", account); + } + + public static String constructDateTime(long daysToAdd, String configToRead) { + + OpenBankingConfigParser parser = OpenBankingConfigParser.getInstance(); + String time = (String) parser.getConfiguration().get(configToRead); + String dateValue = LocalDate.now().plusDays(daysToAdd) + "T" + (OffsetTime.parse(time)); + + OffsetDateTime offSetDateVal = OffsetDateTime.parse(dateValue); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"); + return dateTimeFormatter.format(offSetDateVal); + } + + private void addToCache(String paymentIdValue, JSONObject responseObject) { + + if (domesticVRPs.size() > MAX_LIMIT) { + // Max limit reached + domesticVRPs.remove(domesticVRPsIdQueue.poll()); + } + domesticVRPs.put(paymentIdValue, responseObject); + domesticVRPsIdQueue.add(paymentIdValue); + } +} diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/webapp/WEB-INF/cxf-servlet.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/webapp/WEB-INF/cxf-servlet.xml index e387a505..71138c28 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demo.backend/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -44,9 +44,16 @@ + + + + + + + diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demosite.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demosite.endpoint/pom.xml index e41c09a6..24cf3bb7 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demosite.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.demosite.endpoint/pom.xml @@ -21,8 +21,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> open-banking - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../../pom.xml 4.0.0 @@ -52,7 +52,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/pom.xml index 0a197b68..cdd54d0a 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/pom.xml @@ -18,8 +18,8 @@ open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -63,7 +63,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided @@ -104,7 +104,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.event.notifications.service @@ -115,7 +115,7 @@ provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java index dd39d1bf..9ab95c6e 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java @@ -83,7 +83,7 @@ public Response pollEvents(@Context HttpServletRequest request, @Context HttpSer eventPollingData = parameterMap.get(EventNotificationEndPointConstants.REQUEST). toString().replaceAll("\\\\r|\\\\n|\\r|\\n|\\[|]| ", StringUtils.EMPTY); - if (!eventPollingData.isEmpty()) { + if (StringUtils.isNotBlank(eventPollingData)) { byte[] decodedBytes = Base64.getDecoder().decode(eventPollingData); String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); try { diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java index e0dee0b5..0b621b44 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.event.notifications.endpoint/src/main/java/com/wso2/openbanking/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java @@ -29,7 +29,7 @@ import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; import org.apache.commons.io.IOUtils; -import org.springframework.http.HttpStatus; +import org.apache.http.HttpStatus; import java.io.IOException; @@ -76,7 +76,7 @@ public static JSONObject getJSONObjectPayload(HttpServletRequest request) throws */ public static Response mapEventSubscriptionServiceResponse(EventSubscriptionResponse eventSubscriptionResponse) { int status = eventSubscriptionResponse.getStatus(); - if (HttpStatus.NO_CONTENT.value() == status) { + if (HttpStatus.SC_NO_CONTENT == status) { return Response.status(status) .build(); } else if (eventSubscriptionResponse.getErrorResponse() == null) { @@ -85,12 +85,12 @@ public static Response mapEventSubscriptionServiceResponse(EventSubscriptionResp .entity(eventSubscriptionResponse.getResponseBody()) .build(); } else { - return Response.status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR) .entity(EventNotificationServiceUtil.getErrorDTO(EventNotificationConstants.INVALID_REQUEST, EventNotificationConstants.ERROR_HANDLING_EVENT_SUBSCRIPTION)) .build(); } - } else { + } else { return Response.status(status) .entity(eventSubscriptionResponse.getErrorResponse()) .build(); diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.push.authorization.endpoint/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.push.authorization.endpoint/pom.xml index 3871f338..79a0f7fb 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.push.authorization.endpoint/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.accelerator.push.authorization.endpoint/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml @@ -54,12 +52,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.runtime.identity.authn.filter provided diff --git a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.authentication.webapp/pom.xml b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.authentication.webapp/pom.xml index aec46e33..3f5c2a2c 100644 --- a/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.authentication.webapp/pom.xml +++ b/open-banking-accelerator/internal-apis/internal-webapps/com.wso2.openbanking.authentication.webapp/pom.xml @@ -17,13 +17,11 @@ ~ under the License. --> - + open-banking-accelerator - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.11-SNAPSHOT ../../../pom.xml 4.0.0 @@ -34,12 +32,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions provided diff --git a/open-banking-accelerator/pom.xml b/open-banking-accelerator/pom.xml index 5490dbba..bbb104ba 100644 --- a/open-banking-accelerator/pom.xml +++ b/open-banking-accelerator/pom.xml @@ -17,22 +17,20 @@ ~ under the License. --> - + 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.11-SNAPSHOT ../pom.xml WSO2 Open Banking Accelerator open-banking-accelerator pom - 3.0.0 + 3.2.11-SNAPSHOT components/com.wso2.openbanking.accelerator.common diff --git a/open-banking-react-apps/bfsi-apps/consent-approval-ui/pom.xml b/open-banking-react-apps/bfsi-apps/consent-approval-ui/pom.xml index f4a198de..e9646437 100644 --- a/open-banking-react-apps/bfsi-apps/consent-approval-ui/pom.xml +++ b/open-banking-react-apps/bfsi-apps/consent-approval-ui/pom.xml @@ -22,9 +22,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking-react-apps - 3.0.0 + 3.2.0-SNAPSHOT ../../pom.xml @@ -40,12 +40,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-react-apps/bfsi-apps/consent-manager-dashboard/pom.xml b/open-banking-react-apps/bfsi-apps/consent-manager-dashboard/pom.xml index 666d5482..353ee78a 100644 --- a/open-banking-react-apps/bfsi-apps/consent-manager-dashboard/pom.xml +++ b/open-banking-react-apps/bfsi-apps/consent-manager-dashboard/pom.xml @@ -22,9 +22,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking-react-apps - 3.0.0 + 3.2.0-SNAPSHOT ../../pom.xml @@ -42,12 +42,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-react-apps/bfsi-bff/pom.xml b/open-banking-react-apps/bfsi-bff/pom.xml index 5d3875d6..4ba9084e 100644 --- a/open-banking-react-apps/bfsi-bff/pom.xml +++ b/open-banking-react-apps/bfsi-bff/pom.xml @@ -22,9 +22,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking-react-apps - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml @@ -40,12 +40,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/open-banking-react-apps/pom.xml b/open-banking-react-apps/pom.xml index 280f151e..f19762b1 100644 --- a/open-banking-react-apps/pom.xml +++ b/open-banking-react-apps/pom.xml @@ -23,9 +23,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml diff --git a/open-banking-sample-toolkit/components/aggregator-gateway/pom.xml b/open-banking-sample-toolkit/components/aggregator-gateway/pom.xml index 2267a4c5..a508f53d 100644 --- a/open-banking-sample-toolkit/components/aggregator-gateway/pom.xml +++ b/open-banking-sample-toolkit/components/aggregator-gateway/pom.xml @@ -20,8 +20,8 @@ 4.0.0 open-banking-sample-toolkit - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../pom.xml com.wso2.openbanking.sample.aggregator.gateway @@ -33,7 +33,7 @@ org.wso2.carbon.apimgt.common.gateway - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.gateway diff --git a/open-banking-sample-toolkit/components/aggregator-identity/pom.xml b/open-banking-sample-toolkit/components/aggregator-identity/pom.xml index a8a9309d..df1c7d45 100644 --- a/open-banking-sample-toolkit/components/aggregator-identity/pom.xml +++ b/open-banking-sample-toolkit/components/aggregator-identity/pom.xml @@ -21,8 +21,8 @@ 4.0.0 open-banking-sample-toolkit - com.wso2 - 3.0.0 + com.wso2.openbanking.accelerator + 3.2.0-SNAPSHOT ../../pom.xml com.wso2.openbanking.sample.aggregator.identity @@ -30,7 +30,7 @@ WSO2 Open Banking - Sample Aggregator Identity - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity @@ -46,11 +46,11 @@ json-smart - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions diff --git a/open-banking-sample-toolkit/pom.xml b/open-banking-sample-toolkit/pom.xml index 58e179b1..8cbcb21b 100644 --- a/open-banking-sample-toolkit/pom.xml +++ b/open-banking-sample-toolkit/pom.xml @@ -20,9 +20,9 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.0-SNAPSHOT ../pom.xml open-banking-sample-toolkit diff --git a/pom.xml b/pom.xml index c2a91881..a09d6d67 100644 --- a/pom.xml +++ b/pom.xml @@ -18,10 +18,16 @@ 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking pom - 3.0.0 + 3.2.11-SNAPSHOT + + + org.wso2 + wso2 + 1.4 + @@ -38,6 +44,28 @@ open-banking-accelerator react-apps + + + + org.apache.maven.plugins + maven-javadoc-plugin + + src/main/java + + **/RegistrationErrorDTO.java + + + + + attach-javadocs + + jar + + + + + + npm @@ -253,67 +281,67 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.gateway ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.runtime.identity.authn.filter ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.extensions ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.data.publisher.common ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.keymanager ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.service ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.consent.dao ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.throttler.dao ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.throttler.service ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.event.notifications.service ${project.version} - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.event.notifications.endpoint ${project.version} @@ -481,11 +509,6 @@ javax.servlet ${equinox.javax.servlet.version} - - com.hazelcast - hazelcast - ${com.hazelcast.hazelcast.version} - org.jacoco @@ -685,13 +708,13 @@ ${jstl.version} - org.bouncycastle - bcprov-jdk15on + org.wso2.orbit.org.bouncycastle + bcprov-jdk18on ${org.bouncycastle.version} - org.bouncycastle - bcpkix-jdk15on + org.wso2.orbit.org.bouncycastle + bcpkix-jdk18on ${org.bouncycastle.version} @@ -780,13 +803,12 @@ 3.0.0.wso2v1 0.9.1 1.2 - 1.59 + 1.78.1.wso2v1 [1.6,2) 4.2.3 1.10.1 4.7.3 3.1.0 - 5.0.2 1.0.0.wso2v3 1.12.0 1.2.0.wso2v1 diff --git a/react-apps/pom.xml b/react-apps/pom.xml index 5f9dab7f..0eb7fe37 100644 --- a/react-apps/pom.xml +++ b/react-apps/pom.xml @@ -17,14 +17,13 @@ ~ under the License. --> - + 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator open-banking - 3.0.0 + 3.2.11-SNAPSHOT ../pom.xml diff --git a/react-apps/self-care-portal/pom.xml b/react-apps/self-care-portal/pom.xml index d2078c4e..8265c6f4 100644 --- a/react-apps/self-care-portal/pom.xml +++ b/react-apps/self-care-portal/pom.xml @@ -17,15 +17,13 @@ ~ under the License. --> - + 4.0.0 - com.wso2 + com.wso2.openbanking.accelerator react-apps - 3.0.0 + 3.2.11-SNAPSHOT ../pom.xml @@ -39,12 +37,12 @@ - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.identity provided - com.wso2 + com.wso2.openbanking.accelerator com.wso2.openbanking.accelerator.common provided diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/App.js b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/App.js index 850a5cc5..e284542b 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/App.js +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/App.js @@ -22,6 +22,10 @@ import "./css/App.css"; import { Login } from "./login/login.js"; import { ResponseError } from "./errorPage/index.js"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; +import { logout } from "./login/logout.js"; +import { User } from "./data/User"; + +const idToken = User.idToken; export const App = () => { return ( @@ -29,6 +33,7 @@ export const App = () => { + logout(User?.idToken)} /> ); diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/api/consent-api.js b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/api/consent-api.js index 7b1588fd..e41dea90 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/api/consent-api.js +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/api/consent-api.js @@ -17,11 +17,11 @@ */ import axios from "axios"; -import {CONFIG} from "../config"; +import { CONFIG } from "../config"; import moment from "moment"; import User from "../data/User"; import Cookies from "js-cookie"; -import {specConfigurations} from "../specConfigs/specConfigurations"; +import { specConfigurations } from "../specConfigs"; /** * Get the list of consents from the API. @@ -170,3 +170,20 @@ export const getConsentsFromAPIForSearch = (searchObj, user, appInfo) => { }); }; +export const getRevokeUrl = (consentId, user) => { + const adminUrl = `${CONFIG.BACKEND_URL}/admin/revoke?consentID=${consentId}`; + const defaultUrl = `${CONFIG.BACKEND_URL}/admin/revoke?consentID=${consentId}&userID=${user.email}`; + + return user.role === 'customerCareOfficer' ? adminUrl : defaultUrl; +}; + +export const revokeConsent = (clientId, consentId, user) => { + return axios.delete(getRevokeUrl(consentId, user), { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${Cookies.get(User.CONST.OB_SCP_ACC_TOKEN_P1)}`, + 'x-wso2-client-id': clientId, + 'x-fapi-financial-id': 'open-bank' + }, + }); +}; diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Cards.css b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Cards.css index 40170029..7a4073dc 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Cards.css +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Cards.css @@ -56,10 +56,6 @@ border-color: #AAA7A7; } -.card:hover{ - transform: scale(1.05); -} - .home-tile{ display: flex; flex-direction: row; @@ -68,3 +64,26 @@ margin-bottom: 200px; justify-content: center; } + +.home { + width: 100%; /* Full width */ + min-height: calc(100vh - 100px); /* Full viewport height minus footer height */ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + +.home-content { + display: flex; + flex-direction: column; + width: 100%; + min-height: calc(100vh - 100px); + } + + @media (max-width: 768px) { + .home-content { + flex-direction: column; + } + } diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Footer.css b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Footer.css index fdc5dd55..e91ea7e2 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Footer.css +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Footer.css @@ -1,19 +1,10 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). +/* + * Copyright (c) 2021-2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. * - * 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. + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. */ .Footer { @@ -25,6 +16,8 @@ height: 5.5rem; display: flex; + width: 100%; /* Full width */ + height: 100px; /* Set a fixed height for the footer */ } @@ -51,4 +44,4 @@ p { .footerCol { margin: auto; -} \ No newline at end of file +} diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Leftbar.css b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Leftbar.css index 052e259f..20d1954b 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Leftbar.css +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Leftbar.css @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * 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 @@ -16,7 +16,7 @@ * under the License. */ -.leftbar{ +.leftbar { background: #081247; color: #fff; height: 100%; @@ -26,6 +26,7 @@ @media (max-width: 500px) { .leftbar { width: 150px; + left: 0; } .list-options { font-size: 12px; @@ -44,6 +45,8 @@ flex-direction: column; width: 100%; height: fit-content; + left: 0; + top: 0; } .list-options { diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Profile.css b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Profile.css index 5adf2658..2fa2ad29 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Profile.css +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/Profile.css @@ -49,9 +49,6 @@ text-decoration: none; display: inline-block; cursor: pointer; - - -webkit-box-shadow: 2px 4px 15px -9px rgba(0, 0, 0, 0.53); - box-shadow: 2px 4px 15px -9px rgba(0, 0, 0, 0.53); } .actionButtons { @@ -97,7 +94,6 @@ .accredBox { display: flex; - border: 2px groove rgba(170, 167, 167, 0.16); padding: 0.5em; margin-top: 1rem; margin-bottom: 1rem; @@ -118,6 +114,10 @@ margin-top: 2rem; } +#downloadIcon { + color: #527aff; +} + @media (max-width: 1024px) { .profileMain { margin-top: 0.5rem; diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/SharingDetails.css b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/SharingDetails.css index 36ca823c..e4b0ff75 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/SharingDetails.css +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/css/SharingDetails.css @@ -41,6 +41,10 @@ cursor: pointer; } +.clusterRow:hover { + background-color: #f3f3f3; +} + .clusterContainer { border: 2px groove rgba(170, 167, 167, 0.16); border-radius: 15px; @@ -71,3 +75,4 @@ .permissionsUL { margin-bottom: 0; } + diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/AccountsInfo.jsx b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/AccountsInfo.jsx index 502f11ad..87cc63fe 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/AccountsInfo.jsx +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/AccountsInfo.jsx @@ -1,19 +1,10 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). +/* + * Copyright (c) 2021-2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. * - * 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. + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. */ //AccountsInfo for Default Application @@ -21,8 +12,6 @@ import React from "react"; import {lang, specConfigurations} from "../specConfigs/specConfigurations.js"; import {permissionBindTypes} from "../specConfigs/common"; -let id = 0; - export const AccountsInfo = ({consent, consentType}) => { const consentStatus = consent.currentStatus; @@ -35,9 +24,9 @@ export const AccountsInfo = ({consent, consentType}) => { permissionBindTypes.samePermissionSetForAllAccounts ? ( <>

{keyDatesConfig.accountsInfoLabel}
- {debtorAccounts.map((account) => ( + {debtorAccounts.map((account, index) => ( account.mappingStatus === "active" ? -
  • {account.accountId}
  • +
  • {account.accountId}
  • : <> ))} diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/KeyDatesInfo.jsx b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/KeyDatesInfo.jsx index 2e4034e6..98fd48fb 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/KeyDatesInfo.jsx +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/KeyDatesInfo.jsx @@ -127,7 +127,13 @@ export const KeyDatesInfo = ({consent, infoLabels, consentType}) => { return (
    {keyDatesConfig.keyDatesInfoLabel}
    - {keyDatesMap} +
    + {keyDatesMap.map((item, index) => ( +
    + {item} +
    + ))} +
    ); }; diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/ProfileMain.jsx b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/ProfileMain.jsx index 64e2576f..12a261e5 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/ProfileMain.jsx +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/ProfileMain.jsx @@ -19,6 +19,8 @@ import React, {useState} from "react"; import {Container} from "react-bootstrap"; import {Link} from "react-router-dom"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faDownload } from '@fortawesome/free-solid-svg-icons'; import {withdrawLang, lang} from "../specConfigs"; import ADRLogo from "../images/ADRLogo.png"; import moment from "moment"; @@ -59,7 +61,8 @@ export const ProfileMain = ({consent, infoLabel, appicationName, logoURL}) => { {consent.currentStatus.toLowerCase() === diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/SharingDetails.jsx b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/SharingDetails.jsx index 64d0baff..7b74f662 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/SharingDetails.jsx +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/SharingDetails.jsx @@ -1,19 +1,10 @@ -/** - * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). +/* + * Copyright (c) 2021-2023, WSO2 LLC. (https://www.wso2.com). All Rights Reserved. * - * 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. + * This software is the property of WSO2 LLC. and its suppliers, if any. + * Dissemination of any information or reproduction of any material contained + * herein in any form is strictly forbidden, unless permitted by WSO2 expressly. + * You may not alter or remove any copyright or other notice from copies of this content. */ import React from 'react' @@ -28,7 +19,6 @@ export const SharingDetails = ({consent, infoLabels, consentType}) => {
    -
    diff --git a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/WithdrawStep2.jsx b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/WithdrawStep2.jsx index 6df7df97..935995f7 100644 --- a/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/WithdrawStep2.jsx +++ b/react-apps/self-care-portal/self-care-portal-frontend/accelerator/src/detailedAgreementPage/WithdrawStep2.jsx @@ -23,16 +23,14 @@ import "../css/Buttons.css"; import "../css/DetailedAgreement.css"; import "../css/withdrawal.css"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faCheckCircle, faExclamationCircle, faExclamationTriangle,} from "@fortawesome/free-solid-svg-icons"; +import {faExclamationTriangle} from "@fortawesome/free-solid-svg-icons"; +import { faCheckCircle, faExclamationCircle } from '@fortawesome/free-solid-svg-icons'; import {withdrawLang, specConfigurations} from "../specConfigs"; import ProgressBar from "react-bootstrap/ProgressBar"; import {FourOhFourError} from "../errorPage"; import {PermissionItem} from "../detailedAgreementPage"; -import Axios from "axios"; +import { revokeConsent } from '../api'; import {Modal} from "react-bootstrap"; -import {CONFIG} from "../config"; -import Cookies from "js-cookie"; -import User from "../data/User"; import {getDisplayName, getValueFromConsent} from "../services"; import { UserContext } from "../context/UserContext"; import { ConsentContext } from "../context/ConsentContext"; @@ -47,86 +45,49 @@ export const WithdrawStep2 = ({ match }) => { const [message, setMessage] = useState(""); const [withdrawMessageIcon, setWithdrawMessageIcon] = useState({}); const [withdrawIconId, setWithdrawIconId] = useState(""); - const handleClose = () => setShow(false); - const consents = allContextConsents.consents; - const appInfo = contextAppInfo.appInfo; - const user = currentContextUser.user; + const handleClose = () => setShow(false); const consentId = match.params.id; + const user = currentContextUser.user; + const appInfo = contextAppInfo.appInfo; + const consents = allContextConsents.consents; - var consent; - var clientId; - var consentStatus; - var consentConsentId; - - var matchedConsent; - - matchedConsent = consents.data.filter( - (consent) => consent.consentId === consentId - ); + const matchedConsent = consents.data.find((consent) => consent.consentId === consentId); + + const clientId = matchedConsent?.clientId; + const consentStatus = matchedConsent?.currentStatus; + const consentConsentId = matchedConsent?.consentId; + + const applicationName = getDisplayName(appInfo, clientId); + + const consentAccountResponseDataPermissions = getValueFromConsent( + specConfigurations.consent.permissionsView.permissionsAttribute, + matchedConsent + ) || []; + + const handleRevokeConsent = () => { + revokeConsent(clientId, consentId, user) + .then(response => { + if (response.status === 204) { + setMessage(withdrawLang.withdrawModalSuccessMsg + applicationName); + setWithdrawMessageIcon(faCheckCircle); + setWithdrawIconId('withdrawSuccess'); + } else { + setMessage(withdrawLang.withdrawModalFailMsg); + setWithdrawMessageIcon(faExclamationCircle); + setWithdrawIconId('withdrawFail'); + } + setShow(true); + }) + .catch(error => { + setMessage(withdrawLang.withdrawModalFailMsg + ': ' + error); + setWithdrawMessageIcon(faExclamationCircle); + setWithdrawIconId('withdrawFail'); + setShow(true); + }); +}; - consent = matchedConsent[0]; - clientId = consent.clientId; - consentStatus= consent.currentStatus; - consentConsentId = consent.consentId; - - const applicationName = getDisplayName(appInfo, clientId) - - const adminUrl = `${CONFIG.BACKEND_URL}/admin/revoke?consentID=${consentConsentId}` - const defaultUrl = `${CONFIG.BACKEND_URL}/admin/revoke?consentID=${consentConsentId}&userID=${user.email}` - - var revokeUrl - if(user.role === "customerCareOfficer"){ - revokeUrl = adminUrl; - }else{ - revokeUrl = defaultUrl - } - - const withdrawConsent = () => { - const requestConfig = { - headers: { - "Content-Type": "application/json", - "Authorization": "Bearer " + Cookies.get(User.CONST.OB_SCP_ACC_TOKEN_P1), - "x-fapi-financial-id": "open-bank", - "x-wso2-client-id": clientId, - }, - method: "DELETE", - url: revokeUrl, - }; - - Axios.request(requestConfig) - .then((response) => { - if ((response.status = "204")) { - setMessage( - withdrawLang.withdrawModalSuccessMsg + - applicationName - ); - setWithdrawMessageIcon(faCheckCircle); - setWithdrawIconId("withdrawSuccess"); - setShow(true); - } else { - setMessage( - withdrawLang.withdrawModalFailMsg - ); - setWithdrawMessageIcon(faExclamationCircle); - setWithdrawIconId("withdrawFail"); - } - }) - .catch((error) => { - setMessage( - withdrawLang.withdrawModalFailMsg + ': ' + error); - setWithdrawMessageIcon(faExclamationCircle); - setShow(true); - console.log(error); //Logs a string: Error: Request failed with status code 404 - }); - }; - - var consentAccountResponseDataPermissions = getValueFromConsent( - specConfigurations.consent.permissionsView.permissionsAttribute, consent) - if (consentAccountResponseDataPermissions === "" || consentAccountResponseDataPermissions === undefined) { - consentAccountResponseDataPermissions = []; - } return ( <> {consentStatus.toLowerCase() === specConfigurations.status.authorised.toLowerCase() ? ( @@ -198,7 +159,7 @@ export const WithdrawStep2 = ({ match }) => {