mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 17:17:09 +00:00
Merge pull request #2357 from OpenBankProject/develop
regular release update
This commit is contained in:
commit
0124c52ce9
@ -79,16 +79,6 @@
|
||||
<groupId>org.slf4j</groupId>
|
||||
<version>1.7.26</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
@ -360,16 +350,6 @@
|
||||
<artifactId>geocalc</artifactId>
|
||||
<version>0.5.7</version>
|
||||
</dependency>
|
||||
<!-- embeded kafka for unit test start -->
|
||||
<!-- https://mvnrepository.com/artifact/io.github.embeddedkafka/embedded-kafka -->
|
||||
<dependency>
|
||||
<groupId>io.github.embeddedkafka</groupId>
|
||||
<artifactId>embedded-kafka_2.12</artifactId>
|
||||
<version>2.4.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- embeded kafka for unit test end -->
|
||||
<!-- https://mvnrepository.com/artifact/com.twilio.sdk/twilio -->
|
||||
<dependency>
|
||||
<groupId>com.twilio.sdk</groupId>
|
||||
<artifactId>twilio</artifactId>
|
||||
|
||||
@ -865,7 +865,9 @@ create_just_in_time_entitlements=false
|
||||
# if create_just_in_time_entitlements=true then OBP does the following:
|
||||
# If a user is trying to use a Role (via an endpoint) and the user could grant them selves the required Role(s), then OBP automatically grants the Role!
|
||||
# i.e. if the User already has canCreateEntitlementAtOneBank or canCreateEntitlementAtAnyBank and then OBP will auto grant a role that could be granted by a manual process anyway.
|
||||
# This speeds up the process of granting of roles. Certain roles are excluded from this automation.
|
||||
# This speeds up the process of granting of roles. Certain roles are excluded from this automation:
|
||||
# - CanCreateEntitlementAtOneBank
|
||||
# - CanCreateEntitlementAtAnyBank
|
||||
# If create_just_in_time_entitlements is again set to false after it was true for a while, any auto granted Entitlements to roles are kept in place.
|
||||
# Note: In the entitlements model we set createdbyprocess="create_just_in_time_entitlements". For manual operations we set createdbyprocess="manual"
|
||||
# -------------------------------------------------------------
|
||||
@ -1039,9 +1041,18 @@ outboundAdapterCallContext.generalContext
|
||||
# ------------------------------ default entitlements end ------------------------------
|
||||
|
||||
## Mirror request headers to response
|
||||
# This feature is driven by FAPI requirements. For instance:
|
||||
# The resource server with the FAPI endpoints
|
||||
# - shall set the response header x-fapi-interaction-id to the value
|
||||
# received from the corresponding fapi client request header or to a RFC4122 UUID value
|
||||
# if the request header was not provided to track the interaction, e.g.,
|
||||
# x-fapi-interaction-id: c770aef3-6784-41f7-8e0e-ff5f97bddb3a; and
|
||||
# - shall log the value of x-fapi-interaction-id in the log entry.
|
||||
# mirror_request_headers_to_response=x-fapi-interaction-id,x-jws-signature
|
||||
|
||||
## Echo all request headers to response
|
||||
# Rename all request headers by prepending the word "echo_" and sends them back as response headers
|
||||
# This feature helps to reveal information does every request header sent at a client side really reach a server side
|
||||
echo_request_headers=false
|
||||
|
||||
### enable or disable the feature of send "Force-Error" header, default value is false
|
||||
@ -1275,4 +1286,8 @@ validate_iban=false
|
||||
|
||||
# Show all dependent connector methods for each endpoint. The default value is false.
|
||||
# If set to true, it may consume a significant amount of heap memory.
|
||||
#show_used_connector_methods=false
|
||||
#show_used_connector_methods=false
|
||||
|
||||
# This returns Regulated Entities
|
||||
# sample props regulated_entities = [{"certificate_authority_ca_owner_id":"CY_CBC","entity_certificate_public_key":"-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----","entity_code":"PSD_PICY_CBC!12345","entity_type":"PSD_PI","entity_address":"EXAMPLE COMPANY LTD, 5 SOME STREET","entity_town_city":"SOME CITY","entity_post_code":"1060","entity_country":"CY","entity_web_site":"www.example.com","services":[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]}]
|
||||
regulated_entities = []
|
||||
@ -29,7 +29,6 @@ package bootstrap.liftweb
|
||||
import java.io.{File, FileInputStream}
|
||||
import java.util.stream.Collectors
|
||||
import java.util.{Locale, TimeZone}
|
||||
|
||||
import code.CustomerDependants.MappedCustomerDependant
|
||||
import code.DynamicData.DynamicData
|
||||
import code.DynamicEndpoint.DynamicEndpoint
|
||||
@ -107,6 +106,7 @@ import code.productcollectionitem.MappedProductCollectionItem
|
||||
import code.productfee.ProductFee
|
||||
import code.products.MappedProduct
|
||||
import code.ratelimiting.RateLimiting
|
||||
import code.regulatedentities.MappedRegulatedEntity
|
||||
import code.remotedata.RemotedataActors
|
||||
import code.scheduler.{DataBaseCleanerScheduler, DatabaseDriverScheduler, JobScheduler, MetricsArchiveScheduler}
|
||||
import code.scope.{MappedScope, MappedUserScope}
|
||||
@ -135,6 +135,7 @@ import code.webuiprops.WebUiProps
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.Functions.Implicits._
|
||||
import com.openbankproject.commons.util.{ApiVersion, Functions}
|
||||
|
||||
import javax.mail.internet.MimeMessage
|
||||
import net.liftweb.common._
|
||||
import net.liftweb.db.{DB, DBLogEntry}
|
||||
@ -849,7 +850,7 @@ class Boot extends MdcLoggable {
|
||||
.map[String](_.getClientId)
|
||||
.collect(Collectors.toSet())
|
||||
|
||||
Consumers.consumers.vend.getConsumersFuture().foreach{ consumers =>
|
||||
Consumers.consumers.vend.getConsumersFuture(Nil, None).foreach{ consumers =>
|
||||
consumers.filter(consumer => consumer.isActive.get && !oAuth2ClientIds.contains(consumer.key.get))
|
||||
.foreach(HydraUtil.createHydraClient(_))
|
||||
}
|
||||
@ -1034,6 +1035,7 @@ object ToSchemify {
|
||||
AuthUser,
|
||||
JobScheduler,
|
||||
MappedETag,
|
||||
MappedRegulatedEntity,
|
||||
AtmAttribute,
|
||||
Admin,
|
||||
MappedBank,
|
||||
|
||||
@ -52,6 +52,35 @@ import scala.collection.immutable.List
|
||||
object SwaggerDefinitionsJSON {
|
||||
|
||||
|
||||
lazy val regulatedEntitiesJsonV510: RegulatedEntitiesJsonV510 = RegulatedEntitiesJsonV510(List(regulatedEntityJsonV510))
|
||||
lazy val regulatedEntityJsonV510: RegulatedEntityJsonV510 = RegulatedEntityJsonV510(
|
||||
entity_id = "0af807d7-3c39-43ef-9712-82bcfde1b9ca",
|
||||
certificate_authority_ca_owner_id = "CY_CBC",
|
||||
entity_certificate_public_key = "-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----",
|
||||
entity_name = "EXAMPLE COMPANY LTD",
|
||||
entity_code = "PSD_PICY_CBC!12345",
|
||||
entity_type = "PSD_PI",
|
||||
entity_address = "EXAMPLE COMPANY LTD, 5 SOME STREET",
|
||||
entity_town_city = "SOME CITY",
|
||||
entity_post_code = "1060",
|
||||
entity_country = "CY",
|
||||
entity_web_site = "www.example.com",
|
||||
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""")
|
||||
)
|
||||
|
||||
lazy val regulatedEntityPostJsonV510: RegulatedEntityPostJsonV510 = RegulatedEntityPostJsonV510(
|
||||
certificate_authority_ca_owner_id = "CY_CBC",
|
||||
entity_certificate_public_key = "-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----",
|
||||
entity_name = "EXAMPLE COMPANY LTD",
|
||||
entity_code = "PSD_PICY_CBC!12345",
|
||||
entity_type = "PSD_PI",
|
||||
entity_address = "EXAMPLE COMPANY LTD, 5 SOME STREET",
|
||||
entity_town_city = "SOME CITY",
|
||||
entity_post_code = "1060",
|
||||
entity_country = "CY",
|
||||
entity_web_site = "www.example.com",
|
||||
services = """[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]"""
|
||||
)
|
||||
|
||||
val license = License(
|
||||
id = licenseIdExample.value,
|
||||
@ -2640,6 +2669,31 @@ object SwaggerDefinitionsJSON {
|
||||
enabled = true,
|
||||
created = DateWithDayExampleObject
|
||||
)
|
||||
lazy val pem = "-----BEGIN CERTIFICATE-----\nMIIFIjCCBAqgAwIBAgIIX3qsz7QQxngwDQYJKoZIhvcNAQELBQAwgZ8xCzAJBgNV\r\nBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEPMA0GA1UE\r\nChMGVEVTT0JFMRowGAYDVQQLExFURVNPQkUgT3BlcmF0aW9uczESMBAGA1UEAxMJ\r\nVEVTT0JFIENBMR8wHQYJKoZIhvcNAQkBFhBhZG1pbkB0ZXNvYmUuY29tMQwwCgYD\r\nVQQpEwNWUE4wHhcNMjMwNzE3MDg0MDAwWhcNMjQwNzE3MDg0MDAwWjCBizELMAkG\r\nA1UEBhMCREUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMRQwEgYD\r\nVQQKEwtUZXNvYmUgR21iSDEPMA0GA1UECxMGc3lzb3BzMRIwEAYDVQQDEwlsb2Nh\r\nbGhvc3QxHzAdBgkqhkiG9w0BCQEWEGFkbWluQHRlc29iZS5jb20wggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwxGuWUN1H0d0IeYPYWdLA0I/5BXx4DLO6\r\nzfi1GGJlF8BIXRN0VTJckIY9C3J1RnXDs6p6ufA01iHe1PQdL6VzfcaC3j+jUSgV\r\n1z9ybEUPyUwq3PCCxqoVI9n8yh+O6FDn3dvu/9Q2NtBpJHUBDCLf7OO9TgsFU2sE\r\nMys+Hw5DuuX5n5OQ2VIwH+qlMTQnd+yw5y8FKHqAZT5hE60lF/x6sQnwi58hLGRW\r\nSqo/548c2ZpoeWtnyY1I6PyR7zUYGuhruLY8gVFfLE+610u/lj2wYTXMxntpV+tV\r\nralLFRMhvbqZXW/EpuDb/pEbCnLDNDxq5NarLVDzcHs7VhT9MPChAgMBAAGjggFy\r\nMIIBbjATBgNVHSUEDDAKBggrBgEFBQcDAjAaBgNVHREEEzARgglsb2NhbGhvc3SH\r\nBH8AAAEwggEGBggrBgEFBQcBAwSB+TCB9jAIBgYEAI5GAQEwOAYGBACORgEFMC4w\r\nLBYhaHR0cHM6Ly9leGFtcGxlLm9yZy9wa2lkaXNjbG9zdXJlEwdleGFtcGxlMIGI\r\nBgYEAIGYJwIwfjBMMBEGBwQAgZgnAQMMBlBTUF9BSTARBgcEAIGYJwEBDAZQU1Bf\r\nQVMwEQYHBACBmCcBAgwGUFNQX1BJMBEGBwQAgZgnAQQMBlBTUF9JQwwlRHVtbXkg\r\nRmluYW5jaWFsIFN1cGVydmlzaW9uIEF1dGhvcml0eQwHWFgtREZTQTAlBgYEAI5G\r\nAQYwGwYHBACORgEGAQYHBACORgEGAgYHBACORgEGAzARBglghkgBhvhCAQEEBAMC\r\nB4AwHgYJYIZIAYb4QgENBBEWD3hjYSBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsF\r\nAAOCAQEAKTS7exS9A7rWJLRzWrlHoTu68Avm5g9Dz1GKjgt8rnvj3D21SE14Rf5p\r\n0JWHYH4SiCdnh8Tx+IA7o0TmPJ1JRfAXR3i/5R7TJi/HrnqL+V7SIx2Cuq/hkZEU\r\nAhVs07nnvHURcrlQGwcfn4TbgpCURpCPpYZlNsYySb6BS6I4qFaadHGqMTyEkphV\r\nwfXyB3brmzxj9V4Qgp0t+s/uFuFirWyIayRc9nSSC7vuNVYvib2Kim4y8kvuWpA4\r\nZ51+fFOmBqCqpmwfAADNgDsLJiA/741eBflVd/ZUeAzgOjMCMIaDGlwiwZlePKT7\r\n553GtfsGxZMf05oqfUrQEQfJaU+/+Q==\n-----END CERTIFICATE-----\n"
|
||||
lazy val certificateInfoJsonV510 = CertificateInfoJsonV510(
|
||||
subject_domain_name = "OID.2.5.4.41=VPN, EMAILADDRESS=admin@tesobe.com, CN=TESOBE CA, OU=TESOBE Operations, O=TESOBE, L=Berlin, ST=Berlin, C=DE",
|
||||
issuer_domain_name = "CN=localhost, O=TESOBE GmbH, ST=Berlin, C=DE",
|
||||
not_before = "2022-04-01T10:13:00.000Z",
|
||||
not_after = "2032-04-01T10:13:00.000Z",
|
||||
roles = None,
|
||||
roles_info = Some("PEM Encoded Certificate does not contain PSD2 roles.")
|
||||
)
|
||||
lazy val consumerJsonV510: ConsumerJsonV510 = ConsumerJsonV510(
|
||||
consumer_id = "d0d7b08c-f0ec-4e57-ac99-7d9eafe99225",
|
||||
consumer_key = "d0d7b08c-f0ec-4e57-ac99-7d9eafe99225",
|
||||
consumer_secret = "d0d7b08c-f0ec-4e57-ac99-7d9eafe99225",
|
||||
app_name = "SOFI",
|
||||
app_type = "Web",
|
||||
description = "Account Management",
|
||||
developer_email = ExampleValue.emailExample.value,
|
||||
company = ExampleValue.companyExample.value,
|
||||
redirect_url = "www.openbankproject.com",
|
||||
certificate_pem = pem,
|
||||
certificate_info = Some(certificateInfoJsonV510),
|
||||
created_by_user = resourceUserJSON,
|
||||
enabled = true,
|
||||
created = DateWithDayExampleObject
|
||||
)
|
||||
|
||||
val consumersJson = ConsumersJson(
|
||||
list = List(consumerJSON)
|
||||
@ -4173,15 +4227,6 @@ object SwaggerDefinitionsJSON {
|
||||
val oAuth2ServerJWKURIJson = OAuth2ServerJWKURIJson("https://www.googleapis.com/oauth2/v3/certs")
|
||||
|
||||
val oAuth2ServerJwksUrisJson = OAuth2ServerJwksUrisJson(List(oAuth2ServerJWKURIJson))
|
||||
|
||||
val certificateInfoJsonV510 = CertificateInfoJsonV510(
|
||||
subject_domain_name = "OID.2.5.4.41=VPN, EMAILADDRESS=admin@tesobe.com, CN=TESOBE CA, OU=TESOBE Operations, O=TESOBE, L=Berlin, ST=Berlin, C=DE",
|
||||
issuer_domain_name = "CN=localhost, O=TESOBE GmbH, ST=Berlin, C=DE",
|
||||
not_before = "2022-04-01T10:13:00.000Z",
|
||||
not_after = "2032-04-01T10:13:00.000Z",
|
||||
roles = None,
|
||||
roles_info = Some("PEM Encoded Certificate does not contain PSD2 roles.")
|
||||
)
|
||||
|
||||
val updateAccountRequestJsonV310 = UpdateAccountRequestJsonV310(
|
||||
label = "Label",
|
||||
|
||||
@ -118,6 +118,8 @@ import java.security.AccessControlException
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import code.api.util.FutureUtil.{EndpointContext, EndpointTimeout}
|
||||
import code.api.v2_1_0.OBPAPI2_1_0.Implementations2_1_0
|
||||
import code.api.v2_2_0.OBPAPI2_2_0.Implementations2_2_0
|
||||
import code.etag.MappedETag
|
||||
import code.users.Users
|
||||
import net.liftweb.mapper.By
|
||||
@ -643,7 +645,18 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
val excludedFieldValues = APIUtil.getPropsValue("excluded.response.field.values").map[JArray](it => json.parse(it).asInstanceOf[JArray])
|
||||
|
||||
def successJsonResponseNewStyle(cc: Any, callContext: Option[CallContext], httpCode : Int = 200)(implicit headers: CustomResponseHeaders = CustomResponseHeaders(Nil)) : JsonResponse = {
|
||||
val jsonAst: JValue = ApiSession.processJson((Extraction.decompose(cc)), callContext)
|
||||
val jsonAst: JValue = {
|
||||
val partialFunctionName = callContext.map(_.resourceDocument.map(_.partialFunctionName)).flatten.getOrElse("")
|
||||
if (
|
||||
nameOf(code.api.v5_1_0.APIMethods510.Implementations5_1_0.getMetrics).equals(partialFunctionName) ||
|
||||
nameOf(code.api.v5_0_0.APIMethods500.Implementations5_0_0.getMetricsAtBank).equals(partialFunctionName) ||
|
||||
nameOf(Implementations2_2_0.getConnectorMetrics).equals(partialFunctionName)
|
||||
) {
|
||||
ApiSession.processJson(Extraction.decompose(cc)(CustomJsonFormats.losslessFormats), callContext)
|
||||
} else {
|
||||
ApiSession.processJson((Extraction.decompose(cc)), callContext)
|
||||
}
|
||||
}
|
||||
val excludeOptionalFieldsParam = getHttpRequestUrlParam(callContext.map(_.url).getOrElse(""),"exclude-optional-fields")
|
||||
val excludedResponseBehaviour = APIUtil.getPropsAsBoolValue("excluded.response.behaviour", false)
|
||||
//excludeOptionalFieldsParamValue has top priority, then the excludedResponseBehaviour props.
|
||||
@ -777,20 +790,6 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
}
|
||||
}
|
||||
|
||||
def basicUrlValidation(urlString: String): Boolean = {
|
||||
//in scala test - org.scalatest.FeatureSpecLike.scenario:
|
||||
// redirectUrl = http%3A%2F%2Flocalhost%3A8016%3Foauth_token%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461
|
||||
// URLDecoder.decode(urlString,"UTF-8")-->http://localhost:8016?oauth_token=EBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK&oauth_verifier=63461
|
||||
val regex =
|
||||
"""((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_\/]*)#?(?:[\w]*))?)""".r
|
||||
val decodeUrlValue = URLDecoder.decode(urlString, "UTF-8").trim()
|
||||
decodeUrlValue match {
|
||||
case regex(_*) if (decodeUrlValue.length <= 2048) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** only A-Z, a-z, 0-9,-,_,. =, & and max length <= 2048 */
|
||||
def basicUriAndQueryStringValidation(urlString: String): Boolean = {
|
||||
val regex =
|
||||
@ -2100,7 +2099,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
|
|
||||
|Possible custom url parameters for pagination:
|
||||
|
|
||||
|* limit=NUMBER ==> default value: 50
|
||||
|* limit=NUMBER ==> default value: ${Constant.Pagination.limit}
|
||||
|* offset=NUMBER ==> default value: 0
|
||||
|
|
||||
|eg1:?limit=100&offset=0
|
||||
|
||||
@ -66,6 +66,11 @@ object RoleCombination {
|
||||
|
||||
object ApiRole extends MdcLoggable{
|
||||
|
||||
case class CanCreateRegulatedEntity(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canCreateRegulatedEntity = CanCreateRegulatedEntity()
|
||||
case class CanDeleteRegulatedEntity(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canDeleteRegulatedEntity = CanDeleteRegulatedEntity()
|
||||
|
||||
case class CanSearchWarehouse(requiresBankId: Boolean = false) extends ApiRole
|
||||
lazy val canSearchWarehouse = CanSearchWarehouse()
|
||||
|
||||
|
||||
@ -100,6 +100,9 @@ object ApiTag {
|
||||
val apiTagPSD2PIIS=ResourceDocTag("Confirmation of Funds Service (PIIS)")
|
||||
val apiTagPSD2PIS=ResourceDocTag("Payment Initiation Service (PIS)")
|
||||
|
||||
|
||||
val apiTagDirectory = ResourceDocTag("Directory")
|
||||
|
||||
|
||||
//Note: the followings are for the code generator -- UKOpenBankingV3.1.0
|
||||
val apiTagUkAccountAccess = ResourceDocTag("UK-AccountAccess")
|
||||
|
||||
@ -516,7 +516,12 @@ object ErrorMessages {
|
||||
// Bank related messages
|
||||
val bankIdAlreadyExists = "OBP-34000: Bank Id already exists. Please specify a different value."
|
||||
val updateBankError = "OBP-34001: Could not update the Bank"
|
||||
|
||||
|
||||
val RegulatedEntityNotFound = "OBP-34100: Regulated Entity not found. Please specify a valid value for REGULATED_ENTITY_ID."
|
||||
val RegulatedEntityNotDeleted = "OBP-34101: Regulated Entity cannot be deleted. Please specify a valid value for REGULATED_ENTITY_ID."
|
||||
val RegulatedEntityNotFoundByCertificate = "OBP-34102: Regulated Entity cannot be found by provided certificate."
|
||||
val PostJsonIsNotSigned = "OBP-34110: JWT at the post json cannot be verified."
|
||||
|
||||
// Consents
|
||||
val ConsentNotFound = "OBP-35001: Consent not found by CONSENT_ID. "
|
||||
val ConsentNotBeforeIssue = "OBP-35002: The time Consent-ID token was issued is set in the future. "
|
||||
|
||||
@ -643,7 +643,9 @@ object Glossary extends MdcLoggable {
|
||||
|If Just in Time Entitlements are enabled then OBP does the following:
|
||||
|If a user is trying to use a Role (via an endpoint) and the user could grant them selves the required Role(s), then OBP automatically grants the Role.
|
||||
|i.e. if the User already has canCreateEntitlementAtOneBank or canCreateEntitlementAtAnyBank then OBP will automatically grant a role that would be granted by a manual process anyway.
|
||||
|This speeds up the process of granting of roles. Certain roles are excluded from this automation.
|
||||
|This speeds up the process of granting of roles. Certain roles are excluded from this automation:
|
||||
| - CanCreateEntitlementAtOneBank
|
||||
| - CanCreateEntitlementAtAnyBank
|
||||
|If create_just_in_time_entitlements is again set to false after it was true for a while, any auto granted Entitlements to roles are kept in place.
|
||||
|Note: In the entitlements model we set createdbyprocess=create_just_in_time_entitlements. For manual operations we set createdbyprocess=manual
|
||||
|
|
||||
@ -2115,12 +2117,11 @@ object Glossary extends MdcLoggable {
|
||||
|
|
||||
|Register your App key [HERE]($getServerUrl/consumer-registration)
|
||||
|
|
||||
|Copy and paste the CONSUMER_KEY, CONSUMER_SECRET and REDIRECT_URL for the subsequent steps below.
|
||||
|Copy and paste the CLIENT ID (AKA CONSUMER KEY), CLIENT SECRET (AKA CONSUMER SECRET) and REDIRECT_URL for the subsequent steps below.
|
||||
|
|
||||
|
|
||||
|### Step 2: Initiate the OAuth 2.0 / OpenID Connect Flow
|
||||
|
|
||||
|
|
||||
|Once you have registered your App you should initiate the OAuth2 / OIDC flow using the following URL
|
||||
|
|
||||
|${APIUtil.getHydraPublicServerUrl}/oauth2/auth
|
||||
@ -2129,6 +2130,12 @@ object Glossary extends MdcLoggable {
|
||||
|
|
||||
|${APIUtil.getHydraPublicServerUrl}/oauth2/auth?client_id=YOUR-CLIENT-ID&response_type=code&state=GENERATED_BY_YOUR_APP&scope=openid+offline+ReadAccountsBasic+ReadAccountsDetail+ReadBalances+ReadTransactionsBasic+ReadTransactionsDebits+ReadTransactionsDetail&redirect_uri=https%3A%2F%2FYOUR-APP.com%2Fmain.html
|
||||
|
|
||||
|### Step 3: Exchange the authorisation code for an access token
|
||||
|
|
||||
|The token endpoint is:
|
||||
|
|
||||
|${APIUtil.getHydraPublicServerUrl}/oauth2/token
|
||||
|
|
||||
|
|
||||
|For further information please see [here](https://www.ory.sh/hydra/docs/concepts/login#initiating-the-oauth-20--openid-connect-flow)
|
||||
|
|
||||
|
||||
@ -269,6 +269,15 @@ object JwtUtil extends MdcLoggable {
|
||||
jwk.toPublicJWK.toRSAKey
|
||||
}
|
||||
|
||||
def verifyJwt(jwtString: String, pemEncodedRsaPublicKey: String): Boolean = {
|
||||
// Parse PEM-encoded key to RSA public / private JWK
|
||||
val jwk: JWK = JWK.parseFromPEMEncodedObjects(pemEncodedRsaPublicKey);
|
||||
val rsaPublicKey: RSAKey = jwk.toPublicJWK.toRSAKey
|
||||
val signedJWT = SignedJWT.parse(jwtString)
|
||||
val verifier = new RSASSAVerifier(rsaPublicKey)
|
||||
signedJWT.verify(verifier)
|
||||
}
|
||||
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val jwtToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhhYWQ2NmJkZWZjMWI0M2Q4ZGIyN2U2NWUyZTJlZjMwMTg3OWQzZTgiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTM5NjY4NTQyNDU3ODA4OTI5NTkiLCJhdF9oYXNoIjoiWGlpckZ1cnJ2X0ZxN3RHd25rLWt1QSIsIm5hbWUiOiJNYXJrbyBNaWxpxIciLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDUuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1YZDQ0aG5KNlREby9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BS3hyd2NhZHd6aG00TjR0V2s1RThBdnhpLVpLNmtzNHFnL3M5Ni1jL3Bob3RvLmpwZyIsImdpdmVuX25hbWUiOiJNYXJrbyIsImZhbWlseV9uYW1lIjoiTWlsacSHIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE1NDczMTE3NjAsImV4cCI6MTU0NzMxNTM2MH0.UyOmM0rsO0-G_ibDH3DFogS94GcsNd9GtYVw7j3vSMjO1rZdIraV-N2HUtQN3yHopwdf35A2FEJaag6X8dbvEkJC7_GAynyLIpodoaHNtaLbww6XQSYuQYyF27aPMpROoGZUYkMpB_82LF3PbD4ecDPC2IA5oSyDF4Eya4yn-MzxYmXS7usVWvanREg8iNQSxpu7zZqj4UwhvSIv7wH0vskr_M-PnefQzNTrdUx74i-v9lVqC4E_bF5jWeDGO8k5dqWqg55QuZdyJdSh89KNiIjJXGZDWUBzGfsbetWRnObIgX264fuOW4SpRglUc8fzv41Sc7SSqjqRAFm05t60kg"
|
||||
|
||||
@ -3056,7 +3056,7 @@ object NewStyle extends MdcLoggable{
|
||||
|
||||
private[this] val endpointMappingTTL = APIUtil.getPropsValue(s"endpointMapping.cache.ttl.seconds", "0").toInt
|
||||
|
||||
def getEndpointMappings(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[EndpointMappingT]] = {
|
||||
def getEndpointMappings(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[EndpointMappingT]] = Future{
|
||||
import scala.concurrent.duration._
|
||||
|
||||
validateBankId(bankId, callContext)
|
||||
@ -3064,7 +3064,7 @@ object NewStyle extends MdcLoggable{
|
||||
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
|
||||
CacheKeyFromArguments.buildCacheKey {
|
||||
Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(endpointMappingTTL second) {
|
||||
Future{(EndpointMappingProvider.endpointMappingProvider.vend.getAllEndpointMappings(bankId), callContext)}
|
||||
{(EndpointMappingProvider.endpointMappingProvider.vend.getAllEndpointMappings(bankId), callContext)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import code.util.Helper.MdcLoggable
|
||||
import com.github.dwickern.macros.NameOf
|
||||
import com.nimbusds.jose.jwk.RSAKey
|
||||
import com.nimbusds.jose.util.X509CertUtils
|
||||
import net.liftweb.common.{Box, Failure, Full}
|
||||
import net.liftweb.common.{Box, Failure, Full, Empty}
|
||||
import org.bouncycastle.asn1._
|
||||
import org.bouncycastle.asn1.x509.Extension
|
||||
import org.bouncycastle.asn1.x509.qualified.QCStatement
|
||||
@ -246,5 +246,37 @@ object X509 extends MdcLoggable {
|
||||
case None => Failure(ErrorMessages.X509CannotGetCertificate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getCommonName(pem: Option[String]): Box[String] = {
|
||||
getFieldCommon(pem, "CN")
|
||||
}
|
||||
def getOrganization(pem: Option[String]): Box[String] = {
|
||||
getFieldCommon(pem, "O")
|
||||
}
|
||||
def getOrganizationUnit(pem: Option[String]): Box[String] = {
|
||||
getFieldCommon(pem, "OU")
|
||||
}
|
||||
def getEmailAddress(pem: Option[String]): Box[String] = {
|
||||
getFieldCommon(pem, "EMAILADDRESS")
|
||||
.or(getFieldCommon(pem, "EMAILADDRESS".toLowerCase()))
|
||||
}
|
||||
|
||||
private def getFieldCommon(pem: Option[String], field: String) = {
|
||||
pem match {
|
||||
case Some(unboxedPem) =>
|
||||
extractCertificateInfo(unboxedPem).map { item =>
|
||||
val splitByComma: Array[String] = item.subject_domain_name.split(",")
|
||||
val splitByKeyValuePair: Array[(String, String)] = splitByComma.map(i => i.split("=")(0).trim -> i.split("=")(1).trim)
|
||||
val valuesAsMap: Map[String, List[String]] = splitByKeyValuePair.toList.groupBy(_._1).map { case (k, v) => (k, v.map(_._2)) }
|
||||
val result: String = valuesAsMap.get(field).map(_.mkString).getOrElse("")
|
||||
result
|
||||
} match {
|
||||
case Full(value) if value.isEmpty => Empty
|
||||
case everythingElse => everythingElse
|
||||
}
|
||||
case _ =>
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package code.api.util.newstyle
|
||||
|
||||
import code.api.util.APIUtil.{OBPReturnType, unboxFull}
|
||||
import code.api.util.APIUtil.{OBPReturnType, unboxFull, unboxFullOrFail}
|
||||
import code.api.util.CallContext
|
||||
import code.api.util.ErrorMessages.CreateConsumerError
|
||||
import code.consumer.Consumers
|
||||
import code.model.{AppType, Consumer}
|
||||
|
||||
@ -18,6 +19,7 @@ object Consumer {
|
||||
appType: Option[AppType],
|
||||
description: Option[String],
|
||||
developerEmail: Option[String],
|
||||
company: Option[String],
|
||||
redirectURL: Option[String],
|
||||
createdByUserId: Option[String],
|
||||
clientCertificate: Option[String],
|
||||
@ -33,12 +35,13 @@ object Consumer {
|
||||
developerEmail,
|
||||
redirectURL,
|
||||
createdByUserId,
|
||||
clientCertificate
|
||||
) map {
|
||||
(_, callContext)
|
||||
}
|
||||
clientCertificate,
|
||||
company
|
||||
)
|
||||
} map {
|
||||
unboxFull(_)
|
||||
(_, callContext)
|
||||
} map {
|
||||
x => (unboxFullOrFail(x._1, callContext, CreateConsumerError, 400), x._2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package code.api.util.newstyle
|
||||
|
||||
import code.api.util.APIUtil.{OBPReturnType, unboxFull, unboxFullOrFail}
|
||||
import code.api.util.ErrorMessages.{RegulatedEntityNotDeleted, RegulatedEntityNotFound}
|
||||
import code.api.util.{APIUtil, CallContext}
|
||||
import code.consumer.Consumers
|
||||
import code.model.{AppType, Consumer}
|
||||
import code.regulatedentities.MappedRegulatedEntityProvider
|
||||
import com.openbankproject.commons.model.RegulatedEntityTrait
|
||||
import net.liftweb.common.Box
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
object RegulatedEntityNewStyle {
|
||||
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
|
||||
def createRegulatedEntityNewStyle(certificateAuthorityCaOwnerId: Option[String],
|
||||
entityCertificatePublicKey: Option[String],
|
||||
entityName: Option[String],
|
||||
entityCode: Option[String],
|
||||
entityType: Option[String],
|
||||
entityAddress: Option[String],
|
||||
entityTownCity: Option[String],
|
||||
entityPostCode: Option[String],
|
||||
entityCountry: Option[String],
|
||||
entityWebSite: Option[String],
|
||||
services: Option[String],
|
||||
callContext: Option[CallContext]): OBPReturnType[RegulatedEntityTrait] = {
|
||||
Future {
|
||||
MappedRegulatedEntityProvider.createRegulatedEntity(
|
||||
certificateAuthorityCaOwnerId: Option[String],
|
||||
entityCertificatePublicKey: Option[String],
|
||||
entityName: Option[String],
|
||||
entityCode: Option[String],
|
||||
entityType: Option[String],
|
||||
entityAddress: Option[String],
|
||||
entityTownCity: Option[String],
|
||||
entityPostCode: Option[String],
|
||||
entityCountry: Option[String],
|
||||
entityWebSite: Option[String],
|
||||
services: Option[String]
|
||||
) map {
|
||||
(_, callContext)
|
||||
}
|
||||
} map {
|
||||
unboxFull(_)
|
||||
}
|
||||
}
|
||||
|
||||
def getRegulatedEntitiesNewStyle(callContext: Option[CallContext]): OBPReturnType[List[RegulatedEntityTrait]] = {
|
||||
Future {
|
||||
MappedRegulatedEntityProvider.getRegulatedEntities()
|
||||
} map {
|
||||
(_, callContext)
|
||||
}
|
||||
}
|
||||
def getRegulatedEntityByEntityIdNewStyle(id: String,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[RegulatedEntityTrait] = {
|
||||
Future {
|
||||
MappedRegulatedEntityProvider.getRegulatedEntityByEntityId(id)
|
||||
} map {
|
||||
(_, callContext)
|
||||
} map {
|
||||
x => (unboxFullOrFail(x._1, callContext, RegulatedEntityNotFound, 404), x._2)
|
||||
}
|
||||
}
|
||||
def deleteRegulatedEntityNewStyle(id: String,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[Boolean] = {
|
||||
Future {
|
||||
MappedRegulatedEntityProvider.deleteRegulatedEntity(id)
|
||||
} map {
|
||||
(_, callContext)
|
||||
} map {
|
||||
x => (unboxFullOrFail(x._1, callContext, RegulatedEntityNotDeleted, 400), x._2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -771,6 +771,10 @@ trait APIMethods310 {
|
||||
"Get Consumers",
|
||||
s"""Get the all Consumers.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|${urlParametersDocument(true, true)}
|
||||
|
|
||||
|""",
|
||||
EmptyBody,
|
||||
consumersJson310,
|
||||
@ -790,7 +794,9 @@ trait APIMethods310 {
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConsumers, callContext)
|
||||
consumers <- Consumers.consumers.vend.getConsumersFuture()
|
||||
httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
|
||||
(obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
|
||||
consumers <- Consumers.consumers.vend.getConsumersFuture(obpQueryParams, callContext)
|
||||
users <- Users.users.vend.getUsersByUserIdsFuture(consumers.map(_.createdByUserId.get))
|
||||
} yield {
|
||||
(createConsumersJson(consumers, users), HttpCode.`200`(callContext))
|
||||
|
||||
@ -5295,6 +5295,7 @@ trait APIMethods400 extends MdcLoggable {
|
||||
appType = None,
|
||||
description = Some(postedJson.description),
|
||||
developerEmail = Some(postedJson.developer_email),
|
||||
company = None,
|
||||
redirectURL = Some(postedJson.redirect_url),
|
||||
createdByUserId = Some(u.userId),
|
||||
clientCertificate = Some(postedJson.clientCertificate),
|
||||
|
||||
@ -2,27 +2,33 @@ package code.api.v5_1_0
|
||||
|
||||
|
||||
import code.api.Constant
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{apiCollectionJson400, apiCollectionsJson400, apiInfoJson400, postApiCollectionJson400, revokedConsentJsonV310, _}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
|
||||
import code.api.util.APIUtil._
|
||||
import code.api.util.ApiRole._
|
||||
import code.api.util.ApiTag._
|
||||
import code.api.util.ErrorMessages.{$UserNotLoggedIn, BankNotFound, ConsentNotFound, InvalidJsonFormat, UnknownError, UserNotFoundByUserId, UserNotLoggedIn, _}
|
||||
import code.api.util.FutureUtil.{EndpointContext, EndpointTimeout}
|
||||
import code.api.util.JwtUtil.{getSignedPayloadAsJson, verifyJwt}
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.api.util.X509.{getCommonName, getEmailAddress, getOrganization}
|
||||
import code.api.util._
|
||||
import code.api.v2_0_0.{EntitlementJSONs, JSONFactory200}
|
||||
import code.api.util.newstyle.Consumer.createConsumerNewStyle
|
||||
import code.api.util.newstyle.RegulatedEntityNewStyle.{createRegulatedEntityNewStyle, deleteRegulatedEntityNewStyle, getRegulatedEntitiesNewStyle, getRegulatedEntityByEntityIdNewStyle}
|
||||
import code.api.v2_1_0.{ConsumerRedirectUrlJSON, JSONFactory210}
|
||||
import code.api.v3_0_0.JSONFactory300
|
||||
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
|
||||
import code.api.v3_1_0.ConsentJsonV310
|
||||
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
|
||||
import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400}
|
||||
import code.api.v5_0_0.ConsentJsonV500
|
||||
import code.api.v5_1_0.JSONFactory510.{createRegulatedEntitiesJson, createRegulatedEntityJson}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.bankconnectors.Connector
|
||||
import code.consent.Consents
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.metrics.APIMetrics
|
||||
import code.model.AppType
|
||||
import code.model.dataAccess.MappedBankAccount
|
||||
import code.regulatedentities.MappedRegulatedEntityProvider
|
||||
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
|
||||
import code.userlocks.UserLocksProvider
|
||||
import code.users.Users
|
||||
@ -32,15 +38,14 @@ import code.views.Views
|
||||
import code.views.system.{AccountAccess, ViewDefinition}
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.dto.CustomerAndAttribute
|
||||
import com.openbankproject.commons.model.enums.{AtmAttributeType, UserAttributeType}
|
||||
import com.openbankproject.commons.model.{AtmId, AtmT, BankId, Permission}
|
||||
import com.openbankproject.commons.model._
|
||||
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.json.parse
|
||||
import net.liftweb.json.{compactRender, parse}
|
||||
import net.liftweb.mapper.By
|
||||
import net.liftweb.util.Helpers
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
|
||||
import scala.collection.immutable.{List, Nil}
|
||||
@ -120,6 +125,154 @@ trait APIMethods510 {
|
||||
(SuggestedSessionTimeoutV510(timeoutInSeconds.toString), HttpCode.`200`(cc.callContext))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
regulatedEntities,
|
||||
implementedInApiVersion,
|
||||
nameOf(regulatedEntities),
|
||||
"GET",
|
||||
"/regulated-entities",
|
||||
"Get Regulated Entities",
|
||||
"""Returns information about:
|
||||
|
|
||||
|* Regulated Entities
|
||||
""",
|
||||
EmptyBody,
|
||||
regulatedEntitiesJsonV510,
|
||||
List(UnknownError),
|
||||
apiTagDirectory :: apiTagApi :: Nil)
|
||||
|
||||
lazy val regulatedEntities: OBPEndpoint = {
|
||||
case "regulated-entities" :: Nil JsonGet _ =>
|
||||
cc => implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(entities, callContext) <- getRegulatedEntitiesNewStyle(cc.callContext)
|
||||
} yield {
|
||||
(createRegulatedEntitiesJson(entities), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
getRegulatedEntityById,
|
||||
implementedInApiVersion,
|
||||
nameOf(getRegulatedEntityById),
|
||||
"GET",
|
||||
"/regulated-entities/REGULATED_ENTITY_ID",
|
||||
"Get Regulated Entity",
|
||||
"""Get Regulated Entity By REGULATED_ENTITY_ID
|
||||
""",
|
||||
EmptyBody,
|
||||
regulatedEntitiesJsonV510,
|
||||
List(UnknownError),
|
||||
apiTagDirectory :: apiTagApi :: Nil)
|
||||
|
||||
lazy val getRegulatedEntityById: OBPEndpoint = {
|
||||
case "regulated-entities" :: regulatedEntityId :: Nil JsonGet _ =>
|
||||
cc => implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(regulatedEntityId, cc.callContext)
|
||||
} yield {
|
||||
(createRegulatedEntityJson(entity), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createRegulatedEntity,
|
||||
implementedInApiVersion,
|
||||
nameOf(createRegulatedEntity),
|
||||
"POST",
|
||||
"/regulated-entities",
|
||||
"Create Regulated Entity",
|
||||
s"""Create Regulated Entity
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""",
|
||||
regulatedEntityPostJsonV510,
|
||||
regulatedEntitiesJsonV510,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
InvalidJsonFormat,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagDirectory, apiTagApi),
|
||||
Some(List(canCreateRegulatedEntity))
|
||||
)
|
||||
|
||||
lazy val createRegulatedEntity: OBPEndpoint = {
|
||||
case "regulated-entities" :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
val failMsg = s"$InvalidJsonFormat The Json body should be the $RegulatedEntityPostJsonV510 "
|
||||
for {
|
||||
postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
json.extract[RegulatedEntityPostJsonV510]
|
||||
}
|
||||
failMsg = s"$InvalidJsonFormat The `services` field is not valid JSON"
|
||||
_ <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
|
||||
parse(postedData.services)
|
||||
}
|
||||
(entity, callContext) <- createRegulatedEntityNewStyle(
|
||||
certificateAuthorityCaOwnerId = Some(postedData.certificate_authority_ca_owner_id),
|
||||
entityCertificatePublicKey = Some(postedData.entity_certificate_public_key),
|
||||
entityName = Some(postedData.entity_name),
|
||||
entityCode = Some(postedData.entity_code),
|
||||
entityType = Some(postedData.entity_type),
|
||||
entityAddress = Some(postedData.entity_address),
|
||||
entityTownCity = Some(postedData.entity_town_city),
|
||||
entityPostCode = Some(postedData.entity_post_code),
|
||||
entityCountry = Some(postedData.entity_country),
|
||||
entityWebSite = Some(postedData.entity_web_site),
|
||||
services = Some(postedData.services),
|
||||
cc.callContext
|
||||
)
|
||||
} yield {
|
||||
(createRegulatedEntityJson(entity), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
deleteRegulatedEntity,
|
||||
implementedInApiVersion,
|
||||
nameOf(deleteRegulatedEntity),
|
||||
"DELETE",
|
||||
"/regulated-entities/REGULATED_ENTITY_ID",
|
||||
"Delete Regulated Entity",
|
||||
s"""Delete Regulated Entity specified by REGULATED_ENTITY_ID
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
EmptyBody,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
InvalidConnectorResponse,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagDirectory, apiTagApi),
|
||||
Some(List(canDeleteRegulatedEntity)))
|
||||
|
||||
lazy val deleteRegulatedEntity: OBPEndpoint = {
|
||||
case "regulated-entities" :: regulatedEntityId :: Nil JsonDelete _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(deleted, callContext) <- deleteRegulatedEntityNewStyle(
|
||||
regulatedEntityId: String,
|
||||
cc.callContext: Option[CallContext]
|
||||
)
|
||||
} yield {
|
||||
org.scalameta.logger.elem(deleted)
|
||||
(Full(deleted), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
waitingForGodot,
|
||||
@ -1275,19 +1428,22 @@ trait APIMethods510 {
|
||||
"GET",
|
||||
"/management/metrics",
|
||||
"Get Metrics",
|
||||
s"""Get the all metrics
|
||||
s"""Get API metrics rows. These are records of each REST API call.
|
||||
|
|
||||
|require CanReadMetrics role
|
||||
|
|
||||
|Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics
|
||||
|
|
||||
|Should be able to filter on the following metrics fields
|
||||
|You can filter by the following fields by applying url parameters
|
||||
|
|
||||
|eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
|
||||
|
|
||||
|1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString
|
||||
|1 from_date e.g.:from_date=$DateWithMsExampleString Defaults to the Unix Epoch i.e. ${theEpochTime}
|
||||
|
|
||||
|2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString
|
||||
|2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}
|
||||
|
|
||||
|Note: it is recommended you send a valid from_date (e.g. 5 seconds ago) and to_date (now + 1 second) if you want to get the latest records
|
||||
| Otherwise you may receive stale cached results.
|
||||
|
|
||||
|3 limit (for pagination: defaults to 50) eg:limit=200
|
||||
|
|
||||
@ -1621,6 +1777,149 @@ trait APIMethods510 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createConsumer,
|
||||
implementedInApiVersion,
|
||||
"createConsumer",
|
||||
"POST",
|
||||
"/dynamic-registration/consumers",
|
||||
"Create a Consumer",
|
||||
s"""Create a Consumer (mTLS access).
|
||||
|
|
||||
| JWT payload:
|
||||
| - minimal
|
||||
| { "description":"Description" }
|
||||
| - full
|
||||
| {
|
||||
| "description": "Description",
|
||||
| "app_name": "Tesobe GmbH",
|
||||
| "app_type": "Sofit",
|
||||
| "developer_email": "marko@tesobe.com",
|
||||
| "redirect_url": "http://localhost:8082"
|
||||
| }
|
||||
| Please note that JWT must be signed with the counterpart private kew of the public key used to establish mTLS
|
||||
|
|
||||
|""",
|
||||
ConsumerJwtPostJsonV510("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXNjcmlwdGlvbiI6IkRlc2NyaXB0aW9uIn0.qDnzk1dGK8akdLFRl8fmJV_SeoDjRTDG_eMogCIzZ7M"),
|
||||
consumerJsonV510,
|
||||
List(
|
||||
InvalidJsonFormat,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagDirectory, apiTagConsumer),
|
||||
Some(Nil))
|
||||
|
||||
|
||||
lazy val createConsumer: OBPEndpoint = {
|
||||
case "dynamic-registration" :: "consumers" :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
postedJwt <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
|
||||
json.extract[ConsumerJwtPostJsonV510]
|
||||
}
|
||||
pem = APIUtil.`getPSD2-CERT`(cc.requestHeaders)
|
||||
_ <- Helper.booleanToFuture(PostJsonIsNotSigned, 400, cc.callContext) {
|
||||
verifyJwt(postedJwt.jwt, pem.getOrElse(""))
|
||||
}
|
||||
postedJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, cc.callContext) {
|
||||
parse(getSignedPayloadAsJson(postedJwt.jwt).getOrElse("{}")).extract[ConsumerPostJsonV510]
|
||||
}
|
||||
certificateInfo: CertificateInfoJsonV510 <- Future(X509.getCertificateInfo(pem)) map {
|
||||
unboxFullOrFail(_, cc.callContext, X509GeneralError)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(RegulatedEntityNotFoundByCertificate, 400, cc.callContext) {
|
||||
MappedRegulatedEntityProvider.getRegulatedEntities()
|
||||
.exists(_.entityCertificatePublicKey.replace("""\n""", "") == pem.getOrElse("").replace("""\n""", ""))
|
||||
}
|
||||
(consumer, callContext) <- createConsumerNewStyle(
|
||||
key = Some(Helpers.randomString(40).toLowerCase),
|
||||
secret = Some(Helpers.randomString(40).toLowerCase),
|
||||
isActive = Some(true),
|
||||
name = getCommonName(pem).or(postedJson.app_name) ,
|
||||
appType = postedJson.app_type.map(AppType.valueOf).orElse(Some(AppType.valueOf("Confidential"))),
|
||||
description = Some(postedJson.description),
|
||||
developerEmail = getEmailAddress(pem).or(postedJson.developer_email),
|
||||
company = getOrganization(pem),
|
||||
redirectURL = postedJson.redirect_url,
|
||||
createdByUserId = None,
|
||||
clientCertificate = pem,
|
||||
cc.callContext
|
||||
)
|
||||
} yield {
|
||||
// Format the data as json
|
||||
val json = JSONFactory510.createConsumerJSON(consumer, Some(certificateInfo))
|
||||
// Return
|
||||
(json, HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private def consumerDisabledText() = {
|
||||
if(APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) == false) {
|
||||
"Please note: Your consumer may be disabled as a result of this action."
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
updateConsumerRedirectUrl,
|
||||
implementedInApiVersion,
|
||||
"updateConsumerRedirectUrl",
|
||||
"PUT",
|
||||
"/management/consumers/CONSUMER_ID/consumer/redirect_url",
|
||||
"Update Consumer RedirectUrl",
|
||||
s"""Update an existing redirectUrl for a Consumer specified by CONSUMER_ID.
|
||||
|
|
||||
| ${consumerDisabledText()}
|
||||
|
|
||||
| CONSUMER_ID can be obtained after you register the application.
|
||||
|
|
||||
| Or use the endpoint 'Get Consumers' to get it
|
||||
|
|
||||
""".stripMargin,
|
||||
consumerRedirectUrlJSON,
|
||||
consumerJSON,
|
||||
List(
|
||||
UserNotLoggedIn,
|
||||
UserHasMissingRoles,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagConsumer),
|
||||
Some(List(canUpdateConsumerRedirectUrl))
|
||||
)
|
||||
|
||||
lazy val updateConsumerRedirectUrl: OBPEndpoint = {
|
||||
case "management" :: "consumers" :: consumerId :: "consumer" :: "redirect_url" :: Nil JsonPut json -> _ => {
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) match {
|
||||
case true => Future(Full(Unit))
|
||||
case false => NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUpdateConsumerRedirectUrl, callContext)
|
||||
}
|
||||
postJson <- NewStyle.function.tryons(InvalidJsonFormat, 400, callContext) {
|
||||
json.extract[ConsumerRedirectUrlJSON]
|
||||
}
|
||||
consumer <- NewStyle.function.getConsumerByConsumerId(consumerId, callContext)
|
||||
//only the developer that created the Consumer should be able to edit it
|
||||
_ <- Helper.booleanToFuture(UserNoPermissionUpdateConsumer, 400, callContext) {
|
||||
consumer.createdByUserId.equals(u.userId)
|
||||
}
|
||||
//update the redirectURL and isactive (set to false when change redirectUrl) field in consumer table
|
||||
updatedConsumer <- NewStyle.function.updateConsumer(consumer.id.get, None, None, Some(APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false)), None, None, None, None, Some(postJson.redirect_url), None, callContext)
|
||||
} yield {
|
||||
val json = JSONFactory510.createConsumerJSON(updatedConsumer)
|
||||
(json, HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,21 +30,24 @@ import code.api.Constant
|
||||
import code.api.util.{APIUtil, ConsentJWT, CustomJsonFormats, JwtUtil, Role}
|
||||
import code.api.util.APIUtil.gitCommit
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, transformToLocationFromV140, transformToMetaFromV140}
|
||||
import code.api.v2_1_0.ResourceUserJSON
|
||||
import code.api.v3_0_0.JSONFactory300.{createLocationJson, createMetaJson, transformToAddressFromV300}
|
||||
import code.api.v3_0_0.{AccountIdJson, AccountsIdsJsonV300, AddressJsonV300, OpeningTimesV300}
|
||||
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400}
|
||||
import code.atmattribute.AtmAttribute
|
||||
import code.atms.Atms.Atm
|
||||
import code.users.UserAttribute
|
||||
import code.users.{UserAttribute, Users}
|
||||
import code.views.system.{AccountAccess, ViewDefinition}
|
||||
import com.openbankproject.commons.model.{Address, AtmId, AtmT, BankId, BankIdAccountId, Customer, Location, Meta}
|
||||
import com.openbankproject.commons.model.{Address, AtmId, AtmT, BankId, BankIdAccountId, Customer, Location, Meta, RegulatedEntityTrait}
|
||||
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
|
||||
|
||||
import java.util.Date
|
||||
import code.consent.MappedConsent
|
||||
import code.metrics.APIMetric
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.json.parse
|
||||
import code.model.Consumer
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json.{JValue, parse}
|
||||
|
||||
import scala.collection.immutable.List
|
||||
import scala.util.Try
|
||||
@ -64,6 +67,36 @@ case class APIInfoJsonV510(
|
||||
energy_source : EnergySource400,
|
||||
resource_docs_requires_role: Boolean
|
||||
)
|
||||
|
||||
case class RegulatedEntityJsonV510(
|
||||
entity_id: String,
|
||||
certificate_authority_ca_owner_id: String,
|
||||
entity_certificate_public_key: String,
|
||||
entity_name: String,
|
||||
entity_code: String,
|
||||
entity_type: String,
|
||||
entity_address: String,
|
||||
entity_town_city: String,
|
||||
entity_post_code: String,
|
||||
entity_country: String,
|
||||
entity_web_site: String,
|
||||
services: JValue
|
||||
)
|
||||
case class RegulatedEntityPostJsonV510(
|
||||
certificate_authority_ca_owner_id: String,
|
||||
entity_certificate_public_key: String,
|
||||
entity_name: String,
|
||||
entity_code: String,
|
||||
entity_type: String,
|
||||
entity_address: String,
|
||||
entity_town_city: String,
|
||||
entity_post_code: String,
|
||||
entity_country: String,
|
||||
entity_web_site: String,
|
||||
services: String
|
||||
)
|
||||
case class RegulatedEntitiesJsonV510(entities: List[RegulatedEntityJsonV510])
|
||||
|
||||
case class WaitingForGodotJsonV510(sleep_in_milliseconds: Long)
|
||||
|
||||
case class CertificateInfoJsonV510(
|
||||
@ -250,6 +283,30 @@ case class MetricJsonV510(
|
||||
)
|
||||
case class MetricsJsonV510(metrics: List[MetricJsonV510])
|
||||
|
||||
|
||||
case class ConsumerJwtPostJsonV510(jwt: String)
|
||||
case class ConsumerPostJsonV510(app_name: Option[String],
|
||||
app_type: Option[String],
|
||||
description: String,
|
||||
developer_email: Option[String],
|
||||
redirect_url: Option[String],
|
||||
)
|
||||
case class ConsumerJsonV510(consumer_id: String,
|
||||
consumer_key: String,
|
||||
consumer_secret: String,
|
||||
app_name: String,
|
||||
app_type: String,
|
||||
description: String,
|
||||
developer_email: String,
|
||||
company: String,
|
||||
redirect_url: String,
|
||||
certificate_pem: String,
|
||||
certificate_info: Option[CertificateInfoJsonV510],
|
||||
created_by_user: ResourceUserJSON,
|
||||
enabled: Boolean,
|
||||
created: Date
|
||||
)
|
||||
|
||||
object JSONFactory510 extends CustomJsonFormats {
|
||||
|
||||
def createCustomersIds(customers : List[Customer]): CustomersIdsJsonV510 =
|
||||
@ -534,6 +591,26 @@ object JSONFactory510 extends CustomJsonFormats {
|
||||
UserAttributesResponseJsonV510(userAttribute.map(createUserAttributeJson))
|
||||
}
|
||||
|
||||
def createRegulatedEntityJson(entity: RegulatedEntityTrait): RegulatedEntityJsonV510 = {
|
||||
RegulatedEntityJsonV510(
|
||||
entity_id = entity.entityId,
|
||||
certificate_authority_ca_owner_id = entity.certificateAuthorityCaOwnerId,
|
||||
entity_certificate_public_key = entity.entityCertificatePublicKey,
|
||||
entity_name = entity.entityName,
|
||||
entity_code = entity.entityCode,
|
||||
entity_type = entity.entityType,
|
||||
entity_address = entity.entityAddress,
|
||||
entity_town_city = entity.entityTownCity,
|
||||
entity_post_code = entity.entityPostCode,
|
||||
entity_country = entity.entityCountry,
|
||||
entity_web_site = entity.entityWebSite,
|
||||
services = json.parse(entity.services)
|
||||
)
|
||||
}
|
||||
def createRegulatedEntitiesJson(entities: List[RegulatedEntityTrait]): RegulatedEntitiesJsonV510 = {
|
||||
RegulatedEntitiesJsonV510(entities.map(createRegulatedEntityJson))
|
||||
}
|
||||
|
||||
def createMetricJson(metric: APIMetric): MetricJsonV510 = {
|
||||
MetricJsonV510(
|
||||
user_id = metric.getUserId(),
|
||||
@ -548,8 +625,8 @@ object JSONFactory510 extends CustomJsonFormats {
|
||||
implemented_by_partial_function = metric.getImplementedByPartialFunction(),
|
||||
correlation_id = metric.getCorrelationId(),
|
||||
duration = metric.getDuration(),
|
||||
source_ip = metric.getTargetIp(),
|
||||
target_ip = metric.getSourceIp(),
|
||||
source_ip = metric.getSourceIp(),
|
||||
target_ip = metric.getTargetIp(),
|
||||
response_body = metric.getResponseBody()
|
||||
)
|
||||
}
|
||||
@ -558,6 +635,37 @@ object JSONFactory510 extends CustomJsonFormats {
|
||||
MetricsJsonV510(metrics.map(createMetricJson))
|
||||
}
|
||||
|
||||
def createConsumerJSON(c: Consumer, certificateInfo: Option[CertificateInfoJsonV510] = None): ConsumerJsonV510 = {
|
||||
|
||||
val resourceUserJSON = Users.users.vend.getUserByUserId(c.createdByUserId.toString()) match {
|
||||
case Full(resourceUser) => ResourceUserJSON(
|
||||
user_id = resourceUser.userId,
|
||||
email = resourceUser.emailAddress,
|
||||
provider_id = resourceUser.idGivenByProvider,
|
||||
provider = resourceUser.provider,
|
||||
username = resourceUser.name
|
||||
)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
ConsumerJsonV510(
|
||||
consumer_id = c.consumerId.get,
|
||||
consumer_key = c.key.get,
|
||||
consumer_secret = c.secret.get,
|
||||
app_name = c.name.get,
|
||||
app_type = c.appType.toString(),
|
||||
description = c.description.get,
|
||||
developer_email = c.developerEmail.get,
|
||||
company = c.company.get,
|
||||
redirect_url = c.redirectURL.get,
|
||||
certificate_pem = c.clientCertificate.get,
|
||||
certificate_info = certificateInfo,
|
||||
created_by_user = resourceUserJSON,
|
||||
enabled = c.isActive.get,
|
||||
created = c.createdAt.get
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package code.consumer
|
||||
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.{APIUtil, CallContext, OBPQueryParam}
|
||||
import code.model.{AppType, Consumer, MappedConsumersProvider}
|
||||
import code.remotedata.RemotedataConsumers
|
||||
import com.openbankproject.commons.model.{BankIdAccountId, User, View}
|
||||
@ -31,7 +31,7 @@ trait ConsumersProvider {
|
||||
def getConsumerByConsumerId(consumerId: String): Box[Consumer]
|
||||
def getConsumerByConsumerIdFuture(consumerId: String): Future[Box[Consumer]]
|
||||
def getConsumersByUserIdFuture(userId: String): Future[List[Consumer]]
|
||||
def getConsumersFuture(): Future[List[Consumer]]
|
||||
def getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext]): Future[List[Consumer]]
|
||||
def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String], clientCertificate: Option[String] = None, company: Option[String] = None): Box[Consumer]
|
||||
def deleteConsumer(consumer: Consumer): Boolean
|
||||
def updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
|
||||
@ -64,7 +64,7 @@ class RemotedataConsumersCaseClasses {
|
||||
case class getConsumerByConsumerId(consumerId: String)
|
||||
case class getConsumerByConsumerIdFuture(consumerId: String)
|
||||
case class getConsumersByUserIdFuture(userId: String)
|
||||
case class getConsumersFuture()
|
||||
case class getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext])
|
||||
case class createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String], clientCertificate: Option[String], company: Option[String])
|
||||
case class updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
|
||||
case class deleteConsumer(consumer: Consumer)
|
||||
|
||||
@ -360,7 +360,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
}
|
||||
|
||||
// TODO Cache this as long as fromDate and toDate are in the past (before now)
|
||||
override def getTopApisFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopApi]]] = {
|
||||
override def getTopApisFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopApi]]] = Future{
|
||||
/**
|
||||
* Please note that "var cacheKey = (randomUUID().toString, randomUUID().toString, randomUU
|
||||
* is just a temporary value field with UUID values in order to prevent any ambiguity.
|
||||
@ -369,7 +369,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
*/
|
||||
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
|
||||
CacheKeyFromArguments.buildCacheKey {Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(cachedTopApis seconds){
|
||||
Future{
|
||||
{
|
||||
val fromDate = queryParams.collect { case OBPFromDate(value) => value }.headOption
|
||||
val toDate = queryParams.collect { case OBPToDate(value) => value }.headOption
|
||||
val consumerId = queryParams.collect { case OBPConsumerId(value) => value }.headOption.flatMap(consumerIdToPrimaryKey)
|
||||
@ -440,7 +440,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
}}
|
||||
|
||||
// TODO Cache this as long as fromDate and toDate are in the past (before now)
|
||||
override def getTopConsumersFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopConsumer]]] = {
|
||||
override def getTopConsumersFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopConsumer]]] = Future {
|
||||
/**
|
||||
* Please note that "var cacheKey = (randomUUID().toString, randomUUID().toString, randomUU
|
||||
* is just a temporary value field with UUID values in order to prevent any ambiguity.
|
||||
@ -449,7 +449,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
*/
|
||||
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
|
||||
CacheKeyFromArguments.buildCacheKey {Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(cachedTopConsumers seconds){
|
||||
Future {
|
||||
|
||||
val fromDate = queryParams.collect { case OBPFromDate(value) => value }.headOption
|
||||
val toDate = queryParams.collect { case OBPToDate(value) => value }.headOption
|
||||
val consumerId = queryParams.collect { case OBPConsumerId(value) => value }.headOption.flatMap(consumerIdToPrimaryKey)
|
||||
@ -519,7 +519,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
}
|
||||
tryo(result)
|
||||
}
|
||||
}}}
|
||||
}}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ TESOBE (http://www.tesobe.com/)
|
||||
package code.model
|
||||
import java.util.{Collections, Date}
|
||||
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.{APIUtil, CallContext, OBPAscending, OBPDescending, OBPFromDate, OBPLimit, OBPOffset, OBPOrdering, OBPQueryParam, OBPToDate}
|
||||
import code.api.util.CommonFunctions.validUri
|
||||
import code.api.util.migration.Migration.DbFunction
|
||||
import code.consumer.{Consumers, ConsumersProvider}
|
||||
@ -119,11 +119,26 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable {
|
||||
Future(getConsumersByUserId(userId))
|
||||
}
|
||||
|
||||
def getConsumers(): List[Consumer] = {
|
||||
Consumer.findAll()
|
||||
def getConsumers(queryParams: List[OBPQueryParam], callContext: Option[CallContext]): List[Consumer] = {
|
||||
val limit = queryParams.collect { case OBPLimit(value) => MaxRows[Consumer](value) }.headOption
|
||||
val offset = queryParams.collect { case OBPOffset(value) => StartAt[Consumer](value) }.headOption
|
||||
val fromDate = queryParams.collect { case OBPFromDate(date) => By_>=(Consumer.createdAt, date) }.headOption
|
||||
val toDate = queryParams.collect { case OBPToDate(date) => By_<=(Consumer.createdAt, date) }.headOption
|
||||
val ordering = queryParams.collect {
|
||||
case OBPOrdering(_, direction) =>
|
||||
direction match {
|
||||
case OBPAscending => OrderBy(Consumer.createdAt, Ascending)
|
||||
case OBPDescending => OrderBy(Consumer.createdAt, Descending)
|
||||
}
|
||||
}
|
||||
|
||||
val mapperParams: Seq[QueryParam[Consumer]] = Seq(limit.toSeq, offset.toSeq, fromDate.toSeq, toDate.toSeq, ordering.toSeq).flatten
|
||||
|
||||
Consumer.findAll(mapperParams: _*)
|
||||
}
|
||||
override def getConsumersFuture(): Future[List[Consumer]] = {
|
||||
Future(getConsumers())
|
||||
|
||||
override def getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext]): Future[List[Consumer]] = {
|
||||
Future(getConsumers(httpParams: List[OBPQueryParam], callContext: Option[CallContext]))
|
||||
}
|
||||
|
||||
override def createConsumer(key: Option[String],
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
package code.regulatedentities
|
||||
|
||||
import code.util.MappedUUID
|
||||
import com.openbankproject.commons.model.RegulatedEntityTrait
|
||||
import net.liftweb.common.Box
|
||||
import net.liftweb.common.Box.tryo
|
||||
import net.liftweb.mapper._
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
object MappedRegulatedEntityProvider extends RegulatedEntityProvider {
|
||||
def getRegulatedEntities(): List[RegulatedEntityTrait] = {
|
||||
MappedRegulatedEntity.findAll()
|
||||
}
|
||||
|
||||
override def getRegulatedEntityByEntityId(entityId: String): Box[RegulatedEntityTrait] = {
|
||||
MappedRegulatedEntity.find(By(MappedRegulatedEntity.EntityId, entityId))
|
||||
}
|
||||
|
||||
override def createRegulatedEntity(certificateAuthorityCaOwnerId: Option[String],
|
||||
entityCertificatePublicKey: Option[String],
|
||||
entityName: Option[String],
|
||||
entityCode: Option[String],
|
||||
entityType: Option[String],
|
||||
entityAddress: Option[String],
|
||||
entityTownCity: Option[String],
|
||||
entityPostCode: Option[String],
|
||||
entityCountry: Option[String],
|
||||
entityWebSite: Option[String],
|
||||
services: Option[String]
|
||||
): Box[RegulatedEntityTrait] = {
|
||||
tryo {
|
||||
val entity = MappedRegulatedEntity.create
|
||||
certificateAuthorityCaOwnerId match {
|
||||
case Some(v) => entity.CertificateAuthorityCaOwnerId(v)
|
||||
case None =>
|
||||
}
|
||||
entityCertificatePublicKey match {
|
||||
case Some(v) => entity.EntityCertificatePublicKey(v)
|
||||
case None =>
|
||||
}
|
||||
entityName match {
|
||||
case Some(v) => entity.EntityName(v)
|
||||
case None =>
|
||||
}
|
||||
entityCode match {
|
||||
case Some(v) => entity.EntityCode(v)
|
||||
case None =>
|
||||
}
|
||||
entityType match {
|
||||
case Some(v) => entity.EntityType(v)
|
||||
case None =>
|
||||
}
|
||||
entityAddress match {
|
||||
case Some(v) => entity.EntityAddress(v)
|
||||
case None =>
|
||||
}
|
||||
entityTownCity match {
|
||||
case Some(v) => entity.EntityTownCity(v)
|
||||
case None =>
|
||||
}
|
||||
entityPostCode match {
|
||||
case Some(v) => entity.EntityPostCode(v)
|
||||
case None =>
|
||||
}
|
||||
entityCountry match {
|
||||
case Some(v) => entity.EntityCountry(v)
|
||||
case None =>
|
||||
}
|
||||
entityWebSite match {
|
||||
case Some(v) => entity.EntityWebSite(v)
|
||||
case None =>
|
||||
}
|
||||
services match {
|
||||
case Some(v) => entity.Services(v)
|
||||
case None =>
|
||||
}
|
||||
|
||||
if (entity.validate.isEmpty) {
|
||||
entity.saveMe()
|
||||
} else {
|
||||
throw new Error(entity.validate.map(_.msg.toString()).mkString(";"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def deleteRegulatedEntity(id: String): Box[Boolean] = {
|
||||
tryo(
|
||||
MappedRegulatedEntity.bulkDelete_!!(By(MappedRegulatedEntity.EntityId, id))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MappedRegulatedEntity extends RegulatedEntityTrait with LongKeyedMapper[MappedRegulatedEntity] with IdPK {
|
||||
override def getSingleton = MappedRegulatedEntity
|
||||
object EntityId extends MappedUUID(this)
|
||||
object CertificateAuthorityCaOwnerId extends MappedString(this, 256)
|
||||
object EntityName extends MappedString(this, 256)
|
||||
object EntityCode extends MappedString(this, 50)
|
||||
object EntityCertificatePublicKey extends MappedText(this)
|
||||
object EntityType extends MappedString(this, 50)
|
||||
object EntityAddress extends MappedString(this, 256)
|
||||
object EntityTownCity extends MappedString(this, 50)
|
||||
object EntityPostCode extends MappedString(this, 50)
|
||||
object EntityCountry extends MappedString(this, 50)
|
||||
object EntityWebSite extends MappedString(this, 256)
|
||||
object Services extends MappedText(this)
|
||||
|
||||
|
||||
override def entityId: String = EntityId.get
|
||||
override def certificateAuthorityCaOwnerId: String = CertificateAuthorityCaOwnerId.get
|
||||
override def entityName: String = EntityName.get
|
||||
override def entityCode: String = EntityCode.get
|
||||
override def entityCertificatePublicKey: String = EntityCertificatePublicKey.get
|
||||
override def entityType: String = EntityType.get
|
||||
override def entityAddress: String = EntityAddress.get
|
||||
override def entityTownCity: String = EntityTownCity.get
|
||||
override def entityPostCode: String = EntityPostCode.get
|
||||
override def entityCountry: String = EntityCountry.get
|
||||
override def entityWebSite: String = EntityWebSite.get
|
||||
override def services: String = Services.get
|
||||
|
||||
|
||||
}
|
||||
|
||||
object MappedRegulatedEntity extends MappedRegulatedEntity with LongKeyedMetaMapper[MappedRegulatedEntity] {
|
||||
override def dbTableName = "RegulatedEntity" // define the DB table name
|
||||
override def dbIndexes = Index(CertificateAuthorityCaOwnerId) :: super.dbIndexes
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package code.regulatedentities
|
||||
|
||||
|
||||
import com.openbankproject.commons.model.RegulatedEntityTrait
|
||||
import net.liftweb.common.{Box, Logger}
|
||||
import net.liftweb.util.SimpleInjector
|
||||
|
||||
object RegulatedEntityX extends SimpleInjector {
|
||||
val regulatedEntityProvider = new Inject(buildOne _) {}
|
||||
def buildOne: RegulatedEntityProvider = MappedRegulatedEntityProvider
|
||||
}
|
||||
/* For ProductFee */
|
||||
trait RegulatedEntityProvider {
|
||||
|
||||
private val logger = Logger(classOf[RegulatedEntityProvider])
|
||||
|
||||
def getRegulatedEntities(): List[RegulatedEntityTrait]
|
||||
|
||||
def getRegulatedEntityByEntityId(entityId: String): Box[RegulatedEntityTrait]
|
||||
|
||||
def createRegulatedEntity(certificateAuthorityCaOwnerId: Option[String],
|
||||
entityCertificatePublicKey: Option[String],
|
||||
entityName: Option[String],
|
||||
entityCode: Option[String],
|
||||
entityType: Option[String],
|
||||
entityAddress: Option[String],
|
||||
entityTownCity: Option[String],
|
||||
entityPostCode: Option[String],
|
||||
entityCountry: Option[String],
|
||||
entityWebSite: Option[String],
|
||||
services: Option[String]
|
||||
): Box[RegulatedEntityTrait]
|
||||
|
||||
def deleteRegulatedEntity(id: String): Box[Boolean]
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ package code.remotedata
|
||||
|
||||
import akka.pattern.ask
|
||||
import code.actorsystem.ObpActorInit
|
||||
import code.api.util.{CallContext, OBPQueryParam}
|
||||
import code.consumer.{ConsumersProvider, RemotedataConsumersCaseClasses}
|
||||
import code.model._
|
||||
import net.liftweb.common._
|
||||
@ -35,8 +36,8 @@ object RemotedataConsumers extends ObpActorInit with ConsumersProvider {
|
||||
def getConsumersByUserIdFuture(id: String): Future[List[Consumer]] =
|
||||
(actor ? cc.getConsumersByUserIdFuture(id)).mapTo[List[Consumer]]
|
||||
|
||||
def getConsumersFuture(): Future[List[Consumer]] =
|
||||
(actor ? cc.getConsumersFuture()).mapTo[List[Consumer]]
|
||||
def getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext]): Future[List[Consumer]] =
|
||||
(actor ? cc.getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext])).mapTo[List[Consumer]]
|
||||
|
||||
def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String], clientCertificate: Option[String] = None, company: Option[String] = None): Box[Consumer] = getValueFromFuture(
|
||||
(actor ? cc.createConsumer(key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId, clientCertificate, company)).mapTo[Box[Consumer]]
|
||||
|
||||
@ -2,6 +2,7 @@ package code.remotedata
|
||||
|
||||
import akka.actor.Actor
|
||||
import code.actorsystem.ObpActorHelper
|
||||
import code.api.util.{CallContext, OBPQueryParam}
|
||||
import code.consumer.RemotedataConsumersCaseClasses
|
||||
import code.model.{MappedConsumersProvider, _}
|
||||
import code.util.Helper.MdcLoggable
|
||||
@ -41,9 +42,9 @@ class RemotedataConsumersActor extends Actor with ObpActorHelper with MdcLoggabl
|
||||
logger.debug(s"getConsumersByUserIdFuture($id)")
|
||||
sender ! (mapper.getConsumersByUserId(id))
|
||||
|
||||
case cc.getConsumersFuture() =>
|
||||
case cc.getConsumersFuture(httpParams: List[OBPQueryParam], callContext: Option[CallContext]) =>
|
||||
logger.debug(s"getConsumersFuture()")
|
||||
sender ! (mapper.getConsumers())
|
||||
sender ! (mapper.getConsumers(httpParams: List[OBPQueryParam], callContext: Option[CallContext]))
|
||||
|
||||
case cc.createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String], clientCertificate: Option[String], company: Option[String]) =>
|
||||
logger.debug(s"createConsumer(*****, *****, ${isActive.getOrElse("None")}, ${name.getOrElse("None")}, ${appType.getOrElse("None")}, ${description.getOrElse("None")}, ${developerEmail.getOrElse("None")}, ${redirectURL.getOrElse("None")}, ${createdByUserId.getOrElse("None")}, ${clientCertificate.getOrElse("None")}, ${company.getOrElse("None")})")
|
||||
|
||||
@ -48,8 +48,10 @@ class OAuthWorkedThanks extends MdcLoggable {
|
||||
val redirectUrl = ObpS.param("redirectUrl").map(urlDecode(_))
|
||||
logger.debug(s"OAuthWorkedThanks.thanks.redirectUrl $redirectUrl")
|
||||
//extract the clean(omit the parameters) redirect url from request url
|
||||
val requestedRedirectURL = Helper.extractCleanRedirectURL(redirectUrl.openOr("invalidRequestedRedirectURL")) openOr("invalidRequestedRedirectURL")
|
||||
logger.debug(s"OAuthWorkedThanks.thanks.requestedRedirectURL $requestedRedirectURL")
|
||||
val staticPortionOfRedirectUrl = Helper.getStaticPortionOfRedirectURL(redirectUrl.openOr("invalidRequestedRedirectURL")) openOr("invalidRequestedRedirectURL")
|
||||
val hostOnlyOfRedirectUrlLegacy = Helper.getHostOnlyOfRedirectURL(staticPortionOfRedirectUrl) openOr("invalidRequestedRedirectURL")
|
||||
logger.debug(s"OAuthWorkedThanks.thanks.staticPortionOfRedirectUrl $staticPortionOfRedirectUrl")
|
||||
logger.debug(s"OAuthWorkedThanks.thanks.hostOnlyOfRedirectUrlLegacy $hostOnlyOfRedirectUrlLegacy")
|
||||
|
||||
val requestedOauthToken = Helper.extractOauthToken(redirectUrl.openOr("No Oauth Token here")) openOr("No Oauth Token here")
|
||||
logger.debug(s"OAuthWorkedThanks.thanks.requestedOauthToken $requestedOauthToken")
|
||||
@ -62,13 +64,10 @@ class OAuthWorkedThanks extends MdcLoggable {
|
||||
|
||||
redirectUrl match {
|
||||
case Full(url) =>
|
||||
//this redirect url is checked by following, no open redirect issue.
|
||||
// TODO maybe handle case of extra trailing / on the url ?
|
||||
val incorrectRedirectUrlMessage = s"The validRedirectURL is $validRedirectURL but the staticPortionOfRedirectUrl was $staticPortionOfRedirectUrl"
|
||||
|
||||
val incorrectRedirectUrlMessage = s"The validRedirectURL is $validRedirectURL but the requestedRedirectURL was $requestedRedirectURL"
|
||||
|
||||
|
||||
if(validRedirectURL.equals(requestedRedirectURL)) {
|
||||
//hostOnlyOfRedirectUrlLegacy is deprecated now, we use the staticPortionOfRedirectUrl stead,
|
||||
if(validRedirectURL.equals(staticPortionOfRedirectUrl)|| validRedirectURL.equals(hostOnlyOfRedirectUrlLegacy)) {
|
||||
"#redirect-link [href]" #> url &
|
||||
".app-name"#> appName //there may be several places to be modified in html, so here use the class, not the id.
|
||||
}else{
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package code.util
|
||||
|
||||
import java.net.{Socket, SocketException}
|
||||
import java.net.{Socket, SocketException, URL}
|
||||
import java.util.UUID.randomUUID
|
||||
import java.util.{Date, GregorianCalendar}
|
||||
|
||||
import code.api.util.{APIUtil, CallContext, CallContextLight, CustomJsonFormats}
|
||||
import code.api.{APIFailureNewStyle, Constant}
|
||||
import code.api.util.APIUtil.fullBoxOrException
|
||||
@ -20,7 +19,9 @@ import com.openbankproject.commons.util.{ReflectUtils, RequiredFieldValidation,
|
||||
import com.tesobe.CacheKeyFromArguments
|
||||
import net.liftweb.http.S
|
||||
import net.liftweb.util.Helpers
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
import net.sf.cglib.proxy.{Enhancer, MethodInterceptor, MethodProxy}
|
||||
|
||||
import java.lang.reflect.Method
|
||||
import scala.concurrent.Future
|
||||
import scala.util.Random
|
||||
@ -167,27 +168,30 @@ object Helper extends Loggable {
|
||||
prettyRender(decompose(input))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* extract clean redirect url from input value, because input may have some parameters, such as the following examples <br/>
|
||||
* eg1: http://localhost:8082/oauthcallback?....--> http://localhost:8082 <br/>
|
||||
* eg2: http://localhost:8016?oautallback?=3NLMGV ...--> http://localhost:8016
|
||||
*
|
||||
* @param input a long url with parameters
|
||||
* @return clean redirect url
|
||||
*/
|
||||
def extractCleanRedirectURL(input: String): Box[String] = {
|
||||
/**
|
||||
* pattern eg1: http://xxxxxx?oautxxxx -->http://xxxxxx
|
||||
* pattern eg2: https://xxxxxx/oautxxxx -->http://xxxxxx
|
||||
*/
|
||||
//Note: the pattern should be : val pattern = "(https?):\\/\\/(.*)(?=((\\/)|(\\?))oauthcallback*)".r, but the OAuthTest is different, so add the following logic
|
||||
val pattern = "([A-Za-z][A-Za-z0-9+.-]*):\\/\\/(.*)(?=((\\/)|(\\?))oauth*)".r
|
||||
val validRedirectURL = pattern findFirstIn input
|
||||
// Now for the OAuthTest, the redirect format is : http://localhost:8016?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
|
||||
// It is not the normal case: http://localhost:8082/oauthcallback?oauth_token=LUDKELGJXRDOC1AK1X1TOYIXM5W1AORFJT5KE43B&oauth_verifier=14062
|
||||
// So add the split function to select the first value; eg: Array(http://localhost:8082, thcallback) --> http://localhost:8082
|
||||
val extractCleanURL = validRedirectURL.getOrElse("").split("/oauth")(0)
|
||||
Full(extractCleanURL)
|
||||
*
|
||||
* @param redirectUrl eg: http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
|
||||
* @return http://localhost:8082/oauthcallback
|
||||
*/
|
||||
def getStaticPortionOfRedirectURL(redirectUrl: String): Box[String] = {
|
||||
tryo(redirectUrl.split("\\?")(0)) //return everything before the "?"
|
||||
}
|
||||
|
||||
/**
|
||||
* extract clean redirect url from input value, because input may have some parameters, such as the following examples <br/>
|
||||
* eg1: http://localhost:8082/oauthcallback?....--> http://localhost:8082 <br/>
|
||||
* eg2: http://localhost:8016?oautallback?=3NLMGV ...--> http://localhost:8016
|
||||
*
|
||||
* @param redirectUrl -> http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
|
||||
* @return hostOnlyOfRedirectURL-> http://localhost:8082
|
||||
*/
|
||||
@deprecated("We can not only use hostname as the redirectUrl, now add new method `getStaticPortionOfRedirectURL` ","05.12.2023")
|
||||
def getHostOnlyOfRedirectURL(redirectUrl: String): Box[String] = {
|
||||
val url = new URL(redirectUrl) //eg: http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
|
||||
val protocol = url.getProtocol() // http
|
||||
val authority = url.getAuthority()// localhost:8082, this will contain the port.
|
||||
tryo(s"$protocol://$authority") // http://localhost:8082
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,7 +484,7 @@ object Helper extends Loggable {
|
||||
}else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("consumer_key")){
|
||||
result.asInstanceOf[Box[String]].filter(APIUtil.basicConsumerKeyValidation(_)==SILENCE_IS_GOLDEN)
|
||||
}else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("redirectUrl")){
|
||||
result.asInstanceOf[Box[String]].filter(APIUtil.basicUrlValidation(_))
|
||||
result.asInstanceOf[Box[String]].filter(APIUtil.basicUriAndQueryStringValidation(_))
|
||||
} else{
|
||||
result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN)
|
||||
}
|
||||
|
||||
@ -15,6 +15,13 @@
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>LiftFilter</filter-name>
|
||||
<!--TODO can prepare the white list later -->
|
||||
<!-- We can specify folders or files that we want Liftweb to process.-->
|
||||
<!-- For example, we generally want Liftweb to process all HTML files because they are dynamic, and all the RESTful endpoints.-->
|
||||
<!-- On the other hand, we generally do not want Liftweb to process JS, JPG, and CSS files because they are static.-->
|
||||
<!-- Any processing we can offload from Liftweb is good for performance.-->
|
||||
<!-- Note: Jetty will serve the static files, so they will still appear in the Jetty logs.-->
|
||||
<!-- Ideally, NGINX is used to serve the static files, preventing them from cluttering the Jetty logs.-->
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
120
obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala
Normal file
120
obp-api/src/test/scala/code/api/v5_1_0/RegulatedEntityTest.scala
Normal file
@ -0,0 +1,120 @@
|
||||
package code.api.v5_1_0
|
||||
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.regulatedEntityPostJsonV510
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.{CanCreateRegulatedEntity, CanDeleteRegulatedEntity, CanGetSystemIntegrity}
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn}
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import net.liftweb.json.Serialization._
|
||||
import org.scalatest.Tag
|
||||
|
||||
class RegulatedEntityTest extends V510ServerSetup {
|
||||
/**
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.createRegulatedEntity))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.getRegulatedEntityById))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.getRegulatedEntityById))
|
||||
object ApiEndpoint4 extends Tag(nameOf(Implementations5_1_0.deleteRegulatedEntity))
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") {
|
||||
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "regulated-entities").POST
|
||||
val response510 = makePostRequest(request510, write(regulatedEntityPostJsonV510))
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") {
|
||||
scenario("We will call the endpoint with user credentials but without a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "regulated-entities").POST <@(user1)
|
||||
val response510 = makePostRequest(request510, write(regulatedEntityPostJsonV510))
|
||||
Then("error should be " + UserHasMissingRoles + CanCreateRegulatedEntity)
|
||||
response510.code should equal(403)
|
||||
response510.body.extract[ErrorMessage].message should be (UserHasMissingRoles + CanCreateRegulatedEntity)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") {
|
||||
scenario("We will call the endpoint with user credentials and a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateRegulatedEntity.toString)
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "regulated-entities").POST <@ (user1)
|
||||
val response510 = makePostRequest(request510, write(regulatedEntityPostJsonV510))
|
||||
Then("We get successful response")
|
||||
response510.code should equal(201)
|
||||
response510.body.extract[RegulatedEntityJsonV510]
|
||||
}
|
||||
}
|
||||
|
||||
// ApiEndpoint4 - deleteRegulatedEntity
|
||||
feature(s"test $ApiEndpoint4 version $VersionOfApi - Unauthorized access") {
|
||||
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "regulated-entities" / "some id").DELETE
|
||||
val response510 = makeDeleteRequest(request510)
|
||||
Then("We should get a 401")
|
||||
response510.code should equal(401)
|
||||
response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
}
|
||||
feature(s"test $ApiEndpoint4 version $VersionOfApi - Authorized access") {
|
||||
scenario("We will call the endpoint with user credentials but without a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request510 = (v5_1_0_Request / "regulated-entities" / "some id").DELETE <@ (user1)
|
||||
val response510 = makeDeleteRequest(request510)
|
||||
Then("error should be " + UserHasMissingRoles + CanDeleteRegulatedEntity)
|
||||
response510.code should equal(403)
|
||||
response510.body.extract[ErrorMessage].message should be(UserHasMissingRoles + CanDeleteRegulatedEntity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
feature(s"test $ApiEndpoint1, $ApiEndpoint2, $ApiEndpoint3, $ApiEndpoint4 version $VersionOfApi - CRUD") {
|
||||
scenario("We will call the endpoint with user credentials but without a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
// Create a row
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateRegulatedEntity.toString)
|
||||
val request510 = (v5_1_0_Request / "regulated-entities").POST <@ (user1)
|
||||
val response510 = makePostRequest(request510, write(regulatedEntityPostJsonV510))
|
||||
Then("We get successful response")
|
||||
response510.code should equal(201)
|
||||
val createdRow: RegulatedEntityJsonV510 = response510.body.extract[RegulatedEntityJsonV510]
|
||||
|
||||
// Get the row by id
|
||||
val getRequest510 = (v5_1_0_Request / "regulated-entities" / createdRow.entity_id).GET
|
||||
val getResponse510 = makeGetRequest(getRequest510)
|
||||
getResponse510.code should equal(200)
|
||||
val gottenRow: RegulatedEntityJsonV510 = getResponse510.body.extract[RegulatedEntityJsonV510]
|
||||
|
||||
// TRy to match responses
|
||||
createdRow should equal(gottenRow)
|
||||
|
||||
// Delete the row
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteRegulatedEntity.toString)
|
||||
val deleteRequest510 = (v5_1_0_Request / "regulated-entities" / gottenRow.entity_id).DELETE <@ (user1)
|
||||
val deleteResponse510 = makeDeleteRequest(deleteRequest510)
|
||||
deleteResponse510.code should equal(200)
|
||||
|
||||
|
||||
// Get all rows
|
||||
val getAllRequest510 = (v5_1_0_Request / "regulated-entities").GET
|
||||
val getAllResponse510 = makeGetRequest(getAllRequest510)
|
||||
getAllResponse510.code should equal(200)
|
||||
val allRows = getResponse510.body.extract[RegulatedEntitiesJsonV510]
|
||||
allRows.entities.length should equal(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
package code.bankconnectors.vMay2019
|
||||
|
||||
/*
|
||||
Open Bank Project - API
|
||||
Copyright (C) 2011-2019, TESOBE GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
Email: contact@tesobe.com
|
||||
TESOBE GmbH
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
*/
|
||||
|
||||
|
||||
import code.actorsystem.ObpActorInit
|
||||
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
|
||||
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
|
||||
import code.bankconnectors.Connector
|
||||
import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019
|
||||
import code.bankconnectors.vSept2018._
|
||||
import code.kafka.KafkaHelper
|
||||
import code.setup.{DefaultUsers, KafkaSetup, ServerSetupWithTestData}
|
||||
import com.openbankproject.commons.dto.InBoundGetBanks
|
||||
import com.openbankproject.commons.model._
|
||||
import net.liftweb.common.{Box, Failure, Full}
|
||||
import org.scalatest.Tag
|
||||
|
||||
class StoredProcedureConnector_vDec2019Test extends ServerSetupWithTestData with DefaultUsers with ObpActorInit{
|
||||
|
||||
override implicit val formats = CustomJsonFormats.formats
|
||||
|
||||
object StoredProcedureConnector_vDec2019Test extends Tag("StoredProcedureConnector_vDec2019")
|
||||
|
||||
val callContext = Some(
|
||||
CallContext(
|
||||
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
|
||||
login_user_name = "",
|
||||
is_first = false,
|
||||
app_id = "",
|
||||
app_name = "",
|
||||
time_stamp = "",
|
||||
cbs_token = Some(""),
|
||||
cbs_id = "",
|
||||
session_id = Some(""))),
|
||||
user = Full(resourceUser1)
|
||||
)
|
||||
)
|
||||
|
||||
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
|
||||
|
||||
|
||||
feature("Test all stored_procedure methods") {
|
||||
if (PropsConnectorVersion == "stored_procedure_vDec2019") {
|
||||
// scenario("test `checkBankAccountExists` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
// val checkBankAccountExists = StoredProcedureConnector_vDec2019.checkBankAccountExists(testBankId1,testAccountId1,callContext)
|
||||
// getValueFromFuture(checkBankAccountExists)._1.isDefined equals (true)
|
||||
// }
|
||||
//
|
||||
// scenario("test `getBankAccounts` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
// val checkBankAccountExists = StoredProcedureConnector_vDec2019.checkBankAccountExists(testBankId1,testAccountId1,callContext)
|
||||
// getValueFromFuture(checkBankAccountExists)._1.isDefined equals (true)
|
||||
// }
|
||||
// scenario("test `getBank` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
// val transantionRequests210 = StoredProcedureConnector_vDec2019.getBank(testBankId1, callContext)
|
||||
// getValueFromFuture(transantionRequests210).isDefined equals (true)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// scenario("test `getBanks` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
// val transantionRequests210 = StoredProcedureConnector_vDec2019.getBanks(callContext)
|
||||
// getValueFromFuture(transantionRequests210).isDefined equals (true)
|
||||
// }
|
||||
//
|
||||
// scenario("test `getTransactionRequests210` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
// val transantionRequests210: Box[(List[TransactionRequest], Option[CallContext])] = StoredProcedureConnector_vDec2019.getTransactionRequests210(resourceUser1, null, callContext)
|
||||
// transantionRequests210.isDefined equals(true)
|
||||
// }
|
||||
|
||||
scenario("test `getTransactions` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
|
||||
val transactions = StoredProcedureConnector_vDec2019.getTransactions(testBankId1, testAccountId1, callContext, Nil)
|
||||
val trans = getValueFromFuture(transactions)._1.openOrThrowException("Should not be empty!")
|
||||
trans.head.description.isDefined equals (true)
|
||||
}
|
||||
|
||||
} else {
|
||||
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", StoredProcedureConnector_vDec2019Test) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,157 +0,0 @@
|
||||
package code.bankconnectors.vMay2019
|
||||
|
||||
/*
|
||||
Open Bank Project - API
|
||||
Copyright (C) 2011-2019, TESOBE GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
Email: contact@tesobe.com
|
||||
TESOBE GmbH
|
||||
Osloerstrasse 16/17
|
||||
Berlin 13359, Germany
|
||||
*/
|
||||
|
||||
|
||||
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
|
||||
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
|
||||
import code.bankconnectors.Connector
|
||||
import code.bankconnectors.vSept2018._
|
||||
import code.kafka.KafkaHelper
|
||||
import code.setup.{KafkaSetup, ServerSetupWithTestData}
|
||||
import com.openbankproject.commons.dto.InBoundGetBanks
|
||||
import com.openbankproject.commons.model._
|
||||
import net.liftweb.common.{Box, Failure, Full}
|
||||
import org.scalatest.Tag
|
||||
|
||||
class KafkaMappedConnector_vMay2019Test extends KafkaSetup with ServerSetupWithTestData {
|
||||
|
||||
override implicit val formats = CustomJsonFormats.formats
|
||||
|
||||
object kafkaTest extends Tag("kafkaTest")
|
||||
|
||||
val callContext = Some(
|
||||
CallContext(
|
||||
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
|
||||
login_user_name = "",
|
||||
is_first = false,
|
||||
app_id = "",
|
||||
app_name = "",
|
||||
time_stamp = "",
|
||||
cbs_token = Some(""),
|
||||
cbs_id = "",
|
||||
session_id = Some(""))),
|
||||
user = Full(resourceUser1)
|
||||
)
|
||||
)
|
||||
|
||||
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
|
||||
|
||||
|
||||
feature("Send and retrieve message") {
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
|
||||
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("1st test `getObpConnectorLoopback` method, there no need Adapter message for this method!", kafkaTest) {
|
||||
//This method is only used for `kafka` connector, should first set `connector=kafka_vSept2018` in test.default.props.
|
||||
//and also need to set up `api_instance_id` and `remotedata.timeout` field for it.
|
||||
val propsApiInstanceId = code.api.Constant.ApiInstanceId
|
||||
val propsRemotedataTimeout = APIUtil.getPropsValue("remotedata.timeout").openOrThrowException("connector props filed `remotedata.timeout` not set")
|
||||
|
||||
PropsConnectorVersion contains ("kafka") should be(true)
|
||||
propsApiInstanceId should be("1")
|
||||
propsRemotedataTimeout should be("10")
|
||||
|
||||
When("We call this method, and get the response. ")
|
||||
val future = KafkaHelper.echoKafkaServer
|
||||
val result = future.getContent
|
||||
|
||||
Then("If it return value successfully, that mean api <--> kafka is working well. We only need check one filed of response.")
|
||||
val connectorVersion = result.connectorVersion
|
||||
connectorVersion should be(PropsConnectorVersion)
|
||||
|
||||
Then("For KafkaMappedConnector_vSept2018 connector, we need to make these two methods work `getAuthInfoFirstCbsCall` and `getAuthInfo`")
|
||||
|
||||
val firstAuthInfo: Box[AuthInfo] = for {
|
||||
firstGetAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfoFirstCbsCall("","", callContext)
|
||||
} yield {
|
||||
(firstGetAuthInfo)
|
||||
}
|
||||
firstAuthInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
|
||||
|
||||
val authInfo: Box[AuthInfo] = for {
|
||||
getAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfo(callContext)
|
||||
} yield {
|
||||
getAuthInfo
|
||||
}
|
||||
authInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
|
||||
ignore("ignore test processRequest, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("Send and retrieve message directly to and from kafka", kafkaTest) {
|
||||
val emptyStatusMessage = InboundStatusMessage("", "", "", "")
|
||||
val inBound = InboundGetBanks(InboundAuthInfo("", ""), Status("", List(emptyStatusMessage)), List(InboundBank("1", "2", "3", "4")))
|
||||
When("send a OutboundGetBanks message")
|
||||
|
||||
dispathResponse(inBound)
|
||||
val req = OutboundGetBanks(AuthInfo())
|
||||
|
||||
val future = processRequest[InboundGetBanks](req)
|
||||
val result: Box[InboundGetBanks] = future.getContent
|
||||
|
||||
result should be(Full(inBound))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
feature("Test the getBank error cases") {
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
|
||||
ignore("ignore test getBanks, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBanksFuture -- status.hasError", kafkaTest) {
|
||||
val inbound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InBoundGetBanks]).map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetBanks]
|
||||
//This inBound.status.errorCode != "", so it will throw the error back.
|
||||
val expectedValue = Failure("INTERNAL-"+ inbound.status.errorCode+". + CoreBank-Status:" + inbound.status.backendMessages)
|
||||
dispathResponse(inbound)
|
||||
val future = Connector.connector.vend.getBanks(callContext)
|
||||
|
||||
dispathResponse(inbound)
|
||||
val result = future.getContent
|
||||
result should be(expectedValue)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
|
||||
ignore("ignore test getBanksFuture -- status.hasNoError, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBanksFuture -- status.hasNoError", kafkaTest) {
|
||||
val inbound = Connector.connector.vend.messageDocs
|
||||
.filter(_.exampleInboundMessage.isInstanceOf[InBoundGetBanks])
|
||||
.map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetBanks]
|
||||
.copy(status = Status("", Nil)) // This will set errorCode to "", no it works
|
||||
//This inBound.status.errorCode != "", so it will throw the error back.
|
||||
val expectedValue = Full(inbound.data.head.bankId).toString
|
||||
dispathResponse(inbound)
|
||||
val future = Connector.connector.vend.getBanks(callContext)
|
||||
|
||||
dispathResponse(inbound)
|
||||
val result = future.getContent
|
||||
result.map(_._1.head.bankId).toString should be(expectedValue)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,401 +0,0 @@
|
||||
package code.kafka
|
||||
|
||||
import java.util.{Date, UUID}
|
||||
|
||||
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
|
||||
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
|
||||
import code.api.v2_1_0.TransactionRequestBodyCommonJSON
|
||||
import code.bankconnectors.Connector
|
||||
import code.bankconnectors.vSept2018._
|
||||
import code.setup.{KafkaSetup, ServerSetupWithTestData}
|
||||
import com.openbankproject.commons.dto.{InBoundGetKycChecks, InBoundGetKycMedias, InBoundGetKycStatuses}
|
||||
import com.openbankproject.commons.model._
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import org.scalatest.Tag
|
||||
|
||||
import scala.collection.immutable.List
|
||||
|
||||
class KafkaTest extends KafkaSetup with ServerSetupWithTestData {
|
||||
|
||||
override implicit val formats = CustomJsonFormats.formats
|
||||
|
||||
object kafkaTest extends Tag("kafkaTest")
|
||||
|
||||
val callContext = Some(
|
||||
CallContext(
|
||||
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
|
||||
login_user_name = "",
|
||||
is_first = false,
|
||||
app_id = "",
|
||||
app_name = "",
|
||||
time_stamp = "",
|
||||
cbs_token = Some(""),
|
||||
cbs_id = "",
|
||||
session_id = Some(""))),
|
||||
user = Full(resourceUser1)
|
||||
)
|
||||
)
|
||||
|
||||
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
|
||||
|
||||
|
||||
feature("Send and retrieve message") {
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("1st test `getObpConnectorLoopback` method, there no need Adapter message for this method!", kafkaTest) {
|
||||
//This method is only used for `kafka` connector, should first set `connector=kafka_vSept2018` in test.default.props.
|
||||
//and also need to set up `api_instance_id` and `remotedata.timeout` field for it.
|
||||
val propsApiInstanceId = code.api.Constant.ApiInstanceId
|
||||
val propsRemotedataTimeout = APIUtil.getPropsValue("remotedata.timeout").openOrThrowException("connector props filed `remotedata.timeout` not set")
|
||||
|
||||
PropsConnectorVersion contains ("kafka") should be (true)
|
||||
propsApiInstanceId should be ("1")
|
||||
propsRemotedataTimeout should be ("10")
|
||||
|
||||
When("We call this method, and get the response. ")
|
||||
val future = KafkaHelper.echoKafkaServer
|
||||
val result = future.getContent
|
||||
|
||||
Then("If it return value successfully, that mean api <--> kafka is working well. We only need check one filed of response.")
|
||||
val connectorVersion= result.connectorVersion
|
||||
connectorVersion should be (PropsConnectorVersion)
|
||||
|
||||
Then("For KafkaMappedConnector_vSept2018 connector, we need to make these two methods work `getAuthInfoFirstCbsCall` and `getAuthInfo`")
|
||||
|
||||
val firstAuthInfo: Box[AuthInfo] = for{
|
||||
firstGetAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfoFirstCbsCall("","", callContext)
|
||||
} yield {
|
||||
(firstGetAuthInfo)
|
||||
}
|
||||
firstAuthInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
|
||||
|
||||
val authInfo: Box[AuthInfo] = for{
|
||||
getAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfo(callContext)
|
||||
} yield {
|
||||
getAuthInfo
|
||||
}
|
||||
authInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
|
||||
|
||||
}
|
||||
|
||||
// if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
// ignore("ignore test processRequest, if it is mapped connector", kafkaTest) {}
|
||||
// } else
|
||||
// scenario("Send and retrieve message directly to and from kafka", kafkaTest) {
|
||||
// val emptyStatusMessage = InboundStatusMessage("", "", "", "")
|
||||
// val inBound = InboundGetBanks(InboundAuthInfo("", ""), Status("", List(emptyStatusMessage)), List(InboundBank("1", "2", "3", "4")))
|
||||
// When("send a OutboundGetBanks message")
|
||||
//
|
||||
// dispathResponse(inBound)
|
||||
// val req = OutboundGetBanks(AuthInfo())
|
||||
//
|
||||
// val future = processRequest[InboundGetBanks](req)
|
||||
// val result: Box[InboundGetBanks] = future.getContent
|
||||
//
|
||||
// result should be (Full(inBound))
|
||||
// }
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getKycStatuses, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("test `getKycStatuses` method",kafkaTest) {
|
||||
When("send a OutboundGetKycStatuses api message")
|
||||
val emptyStatusMessage = InboundStatusMessage("", "", "", "")
|
||||
val kycStatusCommons = KycStatusCommons(bankId = "hello_bank_id", customerId = "hello_customer_id", customerNumber = "hello_customer_number", ok = true, date = new Date())
|
||||
val singleInboundBank = List(kycStatusCommons)
|
||||
val inboundAdapterCallContext = InboundAdapterCallContext(correlationId="some_correlationId")
|
||||
val inBound = InBoundGetKycStatuses(inboundAdapterCallContext, Status("", List(emptyStatusMessage)), singleInboundBank)
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getKycStatuses(kycStatusCommons.customerId, Some(CallContext()))
|
||||
|
||||
val result: (Box[List[KycStatus]], Option[CallContext]) = future.getContent
|
||||
val expectResult = Full(singleInboundBank)
|
||||
result._1.toString should be (expectResult.toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getKycChecks, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("test `getKycChecks` method", kafkaTest) {
|
||||
When("send a OutboundGetKycChecks api message")
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process =="obp.getKycChecks").map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetKycChecks]
|
||||
|
||||
dispathResponse(inBound)
|
||||
|
||||
val future = Connector.connector.vend.getKycChecks(inBound.data.head.customerId, Some(CallContext()))
|
||||
val result: (Box[List[KycCheck]], Option[CallContext]) = future.getContent
|
||||
val expectResult = Full(inBound.data)
|
||||
result._1.toString should be (expectResult.toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getKycMedias, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario("test `getKycMedias` method",kafkaTest) {
|
||||
When("send a OutboundetKycMedias api message")
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process =="obp.getKycMedias").map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetKycMedias]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getKycMedias(inBound.data.head.customerId, Some(CallContext()))
|
||||
|
||||
val result: (Box[List[KycMedia]], Option[CallContext]) = future.getContent
|
||||
val expectResult = Full(inBound.data)
|
||||
result._1.toString should be (expectResult.toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getAdapterInfo, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getAdapterInfo method",kafkaTest) {
|
||||
When("send a getAdapterInfo api message")
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getAdapterInfo")).map(_.exampleInboundMessage).head.asInstanceOf[InboundAdapterInfo]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getAdapterInfo(None)
|
||||
|
||||
val result: Box[(InboundAdapterInfoInternal, Option[CallContext])] = future.getContent
|
||||
result.map(_._1) should be (Full(inBound.data))
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getUser, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getUser method",kafkaTest) {
|
||||
When("send a getUser api message")
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getUser")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetUserByUsernamePassword]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val box = Connector.connector.vend.getUser("username","password")
|
||||
|
||||
box.map(_.displayName) should be (Full(inBound.data.displayName))
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBanksFuture, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBanksFuture method", kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getBanks")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBanks]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getBanks(None)
|
||||
|
||||
val result = future.getContent
|
||||
result.map(_._1.head.bankId).toString should be (Full(inBound.data.head.bankId).toString)
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBanks, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBanks method", kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getBanks")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBanks]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val box = Connector.connector.vend.getBanksLegacy(None)
|
||||
|
||||
box.map(_._1.head.bankId).toString should be (Full(inBound.data.head.bankId).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBank, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBank method", kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetBank]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBank]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val box = Connector.connector.vend.getBankLegacy(BankId(""), None)
|
||||
|
||||
box.map(_._1.bankId).toString should be (Full(inBound.data.bankId).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBankFuture, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBankFuture method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetBank]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBank]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getBank(BankId(""), None)
|
||||
val result = future.getContent
|
||||
|
||||
result.map(_._1.bankId).toString should be (Full(inBound.data.bankId).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBankAccountsForUserFuture, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBankAccountsForUserFuture method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccounts]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccounts]
|
||||
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getBankAccountsForUser("", "", callContext)
|
||||
val result = future.getContent
|
||||
|
||||
result.map(_._1.head).toString should be (Full(inBound.data.head).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBankAccountsForUser, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBankAccountsForUser method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccounts]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccounts]
|
||||
dispathResponse(inBound)
|
||||
val box = Connector.connector.vend.getBankAccountsForUserLegacy("","", callContext)
|
||||
|
||||
box.map(_._1.head).toString should be (Full(inBound.data.head).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBankAccount, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBankAccount method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccountbyAccountID]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccountbyAccountID]
|
||||
dispathResponse(inBound)
|
||||
val box = Connector.connector.vend.getBankAccountLegacy(BankId(""), AccountId(""), callContext)
|
||||
|
||||
box.map(_._1.bankId).toString should be (Full(inBound.data.head.bankId).toString)
|
||||
box.map(_._1.accountId).toString should be (Full(inBound.data.head.accountId).toString)
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getBankAccountFuture, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getBankAccountFuture method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccountbyAccountID]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccountbyAccountID]
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.checkBankAccountExists(BankId(""), AccountId(""), callContext)
|
||||
|
||||
val result = future.getContent
|
||||
|
||||
result._1.map(_.accountId.value).toString should be (Full(inBound.data.head.accountId).toString)
|
||||
result._1.map(_.bankId.value).toString should be (Full(inBound.data.head.bankId).toString)
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getChallengeThreshold, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getChallengeThreshold method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetChallengeThreshold]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetChallengeThreshold]
|
||||
dispathResponse(inBound)
|
||||
val future = Connector.connector.vend.getChallengeThreshold("","","","","","","", callContext)
|
||||
|
||||
val result = future.getContent
|
||||
|
||||
result._1.map(_.amount).toString should be (Full(inBound.data.amount).toString)
|
||||
result._1.map(_.currency).toString should be (Full(inBound.data.currency).toString)
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test makePaymentv210, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test makePaymentv210 method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateTransactionId]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateTransactionId]
|
||||
dispathResponse(inBound)
|
||||
|
||||
val fromAccount = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
|
||||
val toAccount = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
|
||||
val transactionRequestId = TransactionRequestId(UUID.randomUUID().toString)
|
||||
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
|
||||
val future = Connector.connector.vend.makePaymentv210(
|
||||
fromAccount,
|
||||
toAccount,
|
||||
transactionRequestId,
|
||||
transactionRequestCommonBody,
|
||||
10,
|
||||
"",
|
||||
TransactionRequestType("SANDBOX_TAN"),
|
||||
"",
|
||||
callContext)
|
||||
|
||||
val result = future.getContent
|
||||
|
||||
result._1.map(_.value).toString should be (Full(inBound.data.id).toString)
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test createChallenge, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test createChallenge method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateChallengeSept2018]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateChallengeSept2018]
|
||||
dispathResponse(inBound)
|
||||
|
||||
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
|
||||
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
|
||||
val future = Connector.connector.vend.createChallenge(
|
||||
account.bankId,
|
||||
account.accountId,
|
||||
"",
|
||||
TransactionRequestType("SANDBOX_TAN"),
|
||||
"",
|
||||
None,
|
||||
callContext)
|
||||
|
||||
val result = future.getContent
|
||||
|
||||
result._1.toString should be (Full(inBound.data.answer).toString)
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test createCounterparty, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test createCounterparty method",kafkaTest) {
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateCounterparty]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateCounterparty]
|
||||
val outBound = Connector.connector.vend.messageDocs.filter(_.exampleOutboundMessage.isInstanceOf[OutboundCreateCounterparty]).map(_.exampleOutboundMessage).head.asInstanceOf[OutboundCreateCounterparty]
|
||||
dispathResponse(inBound)
|
||||
|
||||
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
|
||||
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
|
||||
val box = Connector.connector.vend.createCounterparty(
|
||||
outBound.counterparty.name,
|
||||
outBound.counterparty.description,
|
||||
outBound.counterparty.currency,
|
||||
outBound.counterparty.createdByUserId,
|
||||
outBound.counterparty.thisBankId,
|
||||
outBound.counterparty.thisAccountId,
|
||||
outBound.counterparty.thisViewId,
|
||||
outBound.counterparty.otherAccountRoutingScheme,
|
||||
outBound.counterparty.otherAccountRoutingAddress,
|
||||
outBound.counterparty.otherAccountSecondaryRoutingScheme,
|
||||
outBound.counterparty.otherAccountSecondaryRoutingAddress,
|
||||
outBound.counterparty.otherBankRoutingScheme,
|
||||
outBound.counterparty.otherBankRoutingAddress,
|
||||
outBound.counterparty.otherBranchRoutingScheme,
|
||||
outBound.counterparty.otherBranchRoutingAddress,
|
||||
outBound.counterparty.isBeneficiary,
|
||||
outBound.counterparty.bespoke,
|
||||
callContext)
|
||||
|
||||
|
||||
box.map(_._1.counterpartyId) should be (Full(inBound.data.get.counterpartyId))
|
||||
box.map(_._1.createdByUserId) should be (Full(inBound.data.get.createdByUserId))
|
||||
|
||||
}
|
||||
|
||||
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
|
||||
ignore("ignore test getTransactionRequests210, if it is mapped connector", kafkaTest) {}
|
||||
} else
|
||||
scenario(s"test getTransactionRequests210 method",kafkaTest) {
|
||||
|
||||
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetTransactionRequests210]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetTransactionRequests210]
|
||||
dispathResponse(inBound)
|
||||
|
||||
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
|
||||
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
|
||||
val box = Connector.connector.vend.getTransactionRequests210(
|
||||
resourceUser1,
|
||||
account,
|
||||
callContext)
|
||||
|
||||
box.map(_._1.head.body) should be (inBound.data.head.body)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
package code.setup
|
||||
|
||||
import code.actorsystem.ObpActorSystem
|
||||
import code.api.util.CustomJsonFormats
|
||||
import code.kafka._
|
||||
import code.util.Helper.MdcLoggable
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json.Extraction
|
||||
import net.manub.embeddedkafka.{EmbeddedKafka, EmbeddedKafkaConfig}
|
||||
import org.apache.kafka.common.serialization.{StringDeserializer, StringSerializer}
|
||||
import org.scalatest.{FeatureSpec, _}
|
||||
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.{Await, Future}
|
||||
import scala.concurrent.duration.{Duration, _}
|
||||
|
||||
trait KafkaSetup extends FeatureSpec with EmbeddedKafka with KafkaHelper
|
||||
with GivenWhenThen with BeforeAndAfterAll
|
||||
with Matchers with MdcLoggable {
|
||||
|
||||
|
||||
|
||||
implicit val formats = CustomJsonFormats.formats
|
||||
implicit val config = EmbeddedKafkaConfig(kafkaPort = 9092, zooKeeperPort = 2181) //TODO the port should read from test.default.props, but fail
|
||||
implicit val stringSerializer = new StringSerializer
|
||||
implicit val stringDeserializer = new StringDeserializer
|
||||
|
||||
val requestMapResponseTopics:Map[String, String] = NorthSideConsumer.listOfTopics
|
||||
.map(Topics.createTopicByClassName)
|
||||
.map(pair => (pair.request, pair.response))
|
||||
.toMap
|
||||
val requestTopics = requestMapResponseTopics.keySet
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
||||
EmbeddedKafka.start()
|
||||
|
||||
if(!OBPKafkaConsumer.primaryConsumer.started){
|
||||
val actorSystem = ObpActorSystem.startLocalActorSystem
|
||||
KafkaHelperActors.startLocalKafkaHelperWorkers(actorSystem)
|
||||
// Start North Side Consumer if it's not already started
|
||||
OBPKafkaConsumer.primaryConsumer.start()
|
||||
}
|
||||
}
|
||||
|
||||
override def afterAll(): Unit = {
|
||||
super.afterAll()
|
||||
OBPKafkaConsumer.primaryConsumer.complete()
|
||||
EmbeddedKafka.stop()
|
||||
}
|
||||
|
||||
/**
|
||||
* send an object to kafka as response
|
||||
*
|
||||
* @param inBound inBound object that will send to kafka as a response
|
||||
* @tparam T Outbound type
|
||||
*/
|
||||
def dispathResponse(inBound: AnyRef): Unit = {
|
||||
val inBoundStr = inBound match {
|
||||
case str: String => str
|
||||
case _ =>json.compactRender(Extraction.decompose(inBound))
|
||||
}
|
||||
Future{
|
||||
val requestKeyValue = consumeNumberKeyedMessagesFromTopics(requestTopics, 1, true)
|
||||
val (requestTopic, keyValueList) = requestKeyValue.find(_._2.nonEmpty).get
|
||||
val (key, _) = keyValueList.head
|
||||
val responseTopic = requestMapResponseTopics(requestTopic)
|
||||
publishToKafka(responseTopic, key, inBoundStr)
|
||||
}
|
||||
}
|
||||
|
||||
implicit class FutureExtract[T](future: Future[T]) {
|
||||
def getContent: T = Await.result(future, 10 seconds)
|
||||
}
|
||||
}
|
||||
@ -698,12 +698,18 @@ class APIUtilTest extends FeatureSpec with Matchers with GivenWhenThen with Prop
|
||||
APIUtil.getObpFormatOperationId("xxx") should be ("xxx")
|
||||
}
|
||||
|
||||
feature("test APIUtil.basicUrlValidation method") {
|
||||
feature("test APIUtil.basicUriAndQueryStringValidation method") {
|
||||
val testString1 = "https%3A%2F%2Fapisandbox.openbankproject.com%2Foauth%2Fauthorize%3Fnext%3D%2Fen%2Fusers%2Fmyuser%26oauth_token%3DWTOBT2YRCTMI1BCCF4XAIKRXPLLZDZPFAIL5K03Z%26oauth_verifier%3D45381"
|
||||
val testString2 = "http%3A%2F%2Flocalhost%3A8016%3Foauth_token%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
|
||||
val testString3 = "myapp://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
|
||||
val testString4 = "fb00000000:://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
|
||||
val testString5 = "http://127.0.0.1:8000/oauth/authorize?next=/en/metrics/api/&oauth_token=TN0124OCPRCL4KUJRF5LNLVMRNHTVZPJDBS2PNWU&oauth_verifier=10470"
|
||||
|
||||
APIUtil.basicUrlValidation(testString1) should be (true)
|
||||
APIUtil.basicUrlValidation(testString2) should be (true)
|
||||
APIUtil.basicUriAndQueryStringValidation(testString1) should be (true)
|
||||
APIUtil.basicUriAndQueryStringValidation(testString2) should be (true)
|
||||
APIUtil.basicUriAndQueryStringValidation(testString3) should be (true)
|
||||
APIUtil.basicUriAndQueryStringValidation(testString4) should be (true)
|
||||
APIUtil.basicUriAndQueryStringValidation(testString5) should be (true)
|
||||
|
||||
}
|
||||
|
||||
|
||||
66
obp-api/src/test/scala/code/util/HelperTest.scala
Normal file
66
obp-api/src/test/scala/code/util/HelperTest.scala
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Open Bank Project - API
|
||||
* Copyright (C) 2011-2019, TESOBE GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Email: contact@tesobe.com
|
||||
* TESOBE GmbH.
|
||||
* Osloer Strasse 16/17
|
||||
* Berlin 13359, Germany
|
||||
*
|
||||
* This product includes software developed at
|
||||
* TESOBE (http://www.tesobe.com/)
|
||||
*
|
||||
*/
|
||||
|
||||
package code.util
|
||||
|
||||
|
||||
import code.api.util._
|
||||
import code.setup.PropsReset
|
||||
import org.scalatest.{FeatureSpec, GivenWhenThen, Matchers}
|
||||
|
||||
|
||||
class HelperTest extends FeatureSpec with Matchers with GivenWhenThen with PropsReset {
|
||||
|
||||
feature("test APIUtil.getStaticPortionOfRedirectURL method") {
|
||||
// The redirectURl is `http://localhost:8082/oauthcallback`
|
||||
val testString1 = "http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
|
||||
val testString2 = "http://localhost:8082?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
|
||||
val testString3 = "myapp://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
|
||||
val testString4 = "fb00000000:://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
|
||||
val testString5 = "http://127.0.0.1:8000/oauth/authorize?next=/en/metrics/api/&oauth_token=TN0124OCPRCL4KUJRF5LNLVMRNHTVZPJDBS2PNWU&oauth_verifier=10470"
|
||||
|
||||
Helper.getStaticPortionOfRedirectURL(testString1).head should be("http://localhost:8082/oauthcallback")
|
||||
Helper.getStaticPortionOfRedirectURL(testString2).head should be("http://localhost:8082")
|
||||
Helper.getStaticPortionOfRedirectURL(testString3).head should be("myapp://callback")
|
||||
Helper.getStaticPortionOfRedirectURL(testString4).head should be("fb00000000:://callback")
|
||||
Helper.getStaticPortionOfRedirectURL(testString5).head should be("http://127.0.0.1:8000/oauth/authorize")
|
||||
}
|
||||
|
||||
feature("test APIUtil.getHostOnlyOfRedirectURL method") {
|
||||
// The redirectURl is `http://localhost:8082/oauthcallback`
|
||||
val testString1 = "http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
|
||||
val testString2 = "http://localhost:8082/oauthcallback"
|
||||
val testString3 = "http://localhost:8082?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
|
||||
val testString4 = "http://localhost:8082"
|
||||
|
||||
Helper.getHostOnlyOfRedirectURL(testString1).head should be("http://localhost:8082")
|
||||
Helper.getHostOnlyOfRedirectURL(testString2).head should be("http://localhost:8082")
|
||||
Helper.getHostOnlyOfRedirectURL(testString3).head should be("http://localhost:8082")
|
||||
Helper.getHostOnlyOfRedirectURL(testString4).head should be("http://localhost:8082")
|
||||
}
|
||||
|
||||
}
|
||||
@ -115,6 +115,7 @@ class MappedClassNameTest extends FeatureSpec {
|
||||
"code.model.dataAccess.MappedBank",
|
||||
"code.UserRefreshes.MappedUserRefreshes",
|
||||
"code.DynamicEndpoint.DynamicEndpoint",
|
||||
"code.regulatedentities.MappedRegulatedEntity",
|
||||
"code.CustomerDependants.MappedCustomerDependant")
|
||||
|
||||
val newMappedTypes = ClassScanUtils.findTypes{ info =>
|
||||
|
||||
@ -96,6 +96,22 @@ trait AccountApplication {
|
||||
def status: String
|
||||
}
|
||||
|
||||
|
||||
trait RegulatedEntityTrait {
|
||||
def entityId: String
|
||||
def certificateAuthorityCaOwnerId: String
|
||||
def entityName: String
|
||||
def entityCode: String
|
||||
def entityCertificatePublicKey: String
|
||||
def entityType: String
|
||||
def entityAddress: String
|
||||
def entityTownCity: String
|
||||
def entityPostCode: String
|
||||
def entityCountry: String
|
||||
def entityWebSite: String
|
||||
def services: String
|
||||
}
|
||||
|
||||
trait UserAttributeTrait {
|
||||
def userAttributeId: String
|
||||
def userId: String
|
||||
|
||||
1
pom.xml
1
pom.xml
@ -18,7 +18,6 @@
|
||||
<avro.version>1.8.2</avro.version>
|
||||
<lift.version>3.5.0</lift.version>
|
||||
<jetty.version>9.4.50.v20221201</jetty.version>
|
||||
<log4j.version>2.17.1</log4j.version>
|
||||
<obp-ri.version>2016.11-RC6-SNAPSHOT</obp-ri.version>
|
||||
<!-- Common plugin settings -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user