mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 15:06:50 +00:00
Merge remote-tracking branch 'Simon/develop' into simon-develop
# Conflicts: # obp-api/pom.xml
This commit is contained in:
commit
20f5160a2b
@ -497,8 +497,8 @@ In order to make it work edit your props file in next way:
|
||||
|
||||
```
|
||||
use_consumer_limits=false, In case isn't defined default value is "false"
|
||||
redis_address=YOUR_REDIS_URL_ADDRESS, In case isn't defined default value is 127.0.0.1
|
||||
redis_port=YOUR_REDIS_PORT, In case isn't defined default value is 6379
|
||||
cache.redis.url=YOUR_REDIS_URL_ADDRESS, In case isn't defined default value is 127.0.0.1
|
||||
cache.redis.port=YOUR_REDIS_PORT, In case isn't defined default value is 6379
|
||||
```
|
||||
|
||||
The next types are supported:
|
||||
|
||||
@ -503,7 +503,13 @@
|
||||
<artifactId>jakarta.activation</artifactId>
|
||||
<version>1.2.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.nulab-inc/zxcvbn -->
|
||||
<dependency>
|
||||
<groupId>com.nulab-inc</groupId>
|
||||
<artifactId>zxcvbn</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -856,8 +856,7 @@ featured_apis=elasticSearchWarehouseV300
|
||||
# use_consumer_limits=false
|
||||
# In case isn't defined default value is 60
|
||||
# user_consumer_limit_anonymous_access=100
|
||||
# redis_address=127.0.0.1
|
||||
# redis_port=6379
|
||||
# For the Rate Limiting feature we use Redis cache instance
|
||||
# In case isn't defined default value is root
|
||||
# rate_limiting.exclude_endpoints=root
|
||||
## Default rate limiting for a new consumer
|
||||
|
||||
@ -473,27 +473,30 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{
|
||||
val bookingDate = transaction.startDate.orNull
|
||||
val valueDate = if(transaction.finishDate.isDefined) Some(BgSpecValidation.formatToISODate(transaction.finishDate.orNull)) else None
|
||||
|
||||
val creditorName = transaction.otherBankAccount.map(_.label.display).getOrElse("")
|
||||
val creditorAccountIban = stringOrNone(transaction.otherBankAccount.map(_.iban.getOrElse("")).getOrElse(""))
|
||||
|
||||
val debtorName = stringOrNone(transaction.bankAccount.map(_.label.getOrElse("")).getOrElse(""))
|
||||
val debtorIban = transaction.bankAccount.map(_.accountRoutingAddress.getOrElse("")).getOrElse("")
|
||||
val debtorAccountIdIban = stringOrNone(debtorIban)
|
||||
val out: Boolean = transaction.amount.get.toString().startsWith("-")
|
||||
val in: Boolean = !out
|
||||
|
||||
val isIban = transaction.bankAccount.flatMap(_.accountRoutingScheme.map(_.toUpperCase == "IBAN")).getOrElse(false)
|
||||
// Creditor
|
||||
val creditorName = if(in) transaction.otherBankAccount.map(_.label.display) else None
|
||||
val creditorAccountIban = if(in) {
|
||||
val creditorIban = if(isIban) transaction.otherBankAccount.map(_.iban.getOrElse("")) else Some("")
|
||||
Some(BgTransactionAccountJson(iban = creditorIban))
|
||||
} else None
|
||||
|
||||
// Debtor
|
||||
val debtorName = if(out) transaction.bankAccount.map(_.label.getOrElse("")) else None
|
||||
val debtorAccountIban = if(out) {
|
||||
val debtorIban = if(isIban) transaction.bankAccount.map(_.accountRoutingAddress.getOrElse("")) else Some("")
|
||||
Some(BgTransactionAccountJson(iban = debtorIban))
|
||||
} else None
|
||||
|
||||
TransactionJsonV13(
|
||||
transactionId = transaction.id.value,
|
||||
creditorName = stringOrNone(creditorName),
|
||||
creditorAccount =
|
||||
if(creditorAccountIban.isEmpty)
|
||||
None
|
||||
else
|
||||
Some(BgTransactionAccountJson(iban=creditorAccountIban)),
|
||||
creditorName = creditorName,
|
||||
creditorAccount = creditorAccountIban,
|
||||
debtorName = debtorName,
|
||||
debtorAccount =
|
||||
if(debtorAccountIdIban.isEmpty)
|
||||
None
|
||||
else
|
||||
Some(BgTransactionAccountJson(iban = debtorAccountIdIban)),
|
||||
debtorAccount = debtorAccountIban,
|
||||
transactionAmount = AmountOfMoneyV13(
|
||||
transaction.currency.getOrElse(""),
|
||||
if(bgRemoveSignOfAmounts)
|
||||
|
||||
@ -3974,7 +3974,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
tpp <- BerlinGroupSigning.getTppByCertificate(certificate, cc)
|
||||
} yield {
|
||||
if (tpp.nonEmpty) {
|
||||
val hasRole = tpp.exists(_.services.contains(serviceProvider))
|
||||
val berlinGroupRole = PemCertificateRole.toBerlinGroup(serviceProvider)
|
||||
val hasRole = tpp.exists(_.services.contains(berlinGroupRole))
|
||||
if (hasRole) {
|
||||
Full(true)
|
||||
} else {
|
||||
|
||||
21
obp-api/src/main/scala/code/api/util/PasswordUtil.scala
Normal file
21
obp-api/src/main/scala/code/api/util/PasswordUtil.scala
Normal file
@ -0,0 +1,21 @@
|
||||
package code.api.util
|
||||
|
||||
import com.nulabinc.zxcvbn.Zxcvbn
|
||||
import com.nulabinc.zxcvbn.Strength
|
||||
|
||||
object PasswordUtil {
|
||||
|
||||
private val zxcvbn = new Zxcvbn()
|
||||
|
||||
/** Check password strength score: 0 (very weak) to 4 (very strong) */
|
||||
def getStrength(password: String): Strength = {
|
||||
zxcvbn.measure(password)
|
||||
}
|
||||
|
||||
/** Recommend minimum score of 3 (strong) */
|
||||
def isAcceptable(password: String, minScore: Int = 3): Boolean = {
|
||||
getStrength(password).getScore >= minScore
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -185,14 +185,32 @@ class AccountInformationServiceAISApiTest extends BerlinGroupServerSetupV1_3 wit
|
||||
user1,
|
||||
PostViewJsonV400(view_id = Constant.SYSTEM_READ_TRANSACTIONS_BERLIN_GROUP_VIEW_ID, is_system = true)
|
||||
)
|
||||
val requestGet = (V1_3_BG / "accounts" /testAccountId1.value/ "transactions").GET <@ (user1)
|
||||
val requestGet = (V1_3_BG / "accounts" /testAccountId1.value/ "transactions").GET <@ (user1) <<? List(("bookingStatus", "both"))
|
||||
val response: APIResponse = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[TransactionsJsonV13].account.iban should not be ("")
|
||||
// response.body.extract[TransactionsJsonV13].transactions.booked.head.length >0 should be (true)
|
||||
response.body.extract[TransactionsJsonV13].transactions.pending.head.length >0 should be (true)
|
||||
response.body.extract[TransactionsJsonV13].transactions.pending.head.nonEmpty should be (true)
|
||||
response.body.extract[TransactionsJsonV13].transactions.booked.nonEmpty should be (true)
|
||||
|
||||
|
||||
val requestGet2 = (V1_3_BG / "accounts" / testAccountId1.value / "transactions").GET <@ (user1) <<? List(("bookingStatus", "booked"))
|
||||
val response2: APIResponse = makeGetRequest(requestGet2)
|
||||
Then("We should get a 200 ")
|
||||
response2.code should equal(200)
|
||||
response2.body.extract[TransactionsJsonV13].account.iban should not be ("")
|
||||
response2.body.extract[TransactionsJsonV13].transactions.pending.isEmpty should be(true)
|
||||
response2.body.extract[TransactionsJsonV13].transactions.booked.nonEmpty should be(true)
|
||||
|
||||
val requestGet3 = (V1_3_BG / "accounts" / testAccountId1.value / "transactions").GET <@ (user1) <<? List(("bookingStatus", "pending"))
|
||||
val response3: APIResponse = makeGetRequest(requestGet3)
|
||||
Then("We should get a 200 ")
|
||||
response3.code should equal(200)
|
||||
response3.body.extract[TransactionsJsonV13].account.iban should not be ("")
|
||||
response3.body.extract[TransactionsJsonV13].transactions.pending.nonEmpty should be(true)
|
||||
response3.body.extract[TransactionsJsonV13].transactions.booked.isEmpty should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,13 +232,13 @@ class AccountInformationServiceAISApiTest extends BerlinGroupServerSetupV1_3 wit
|
||||
user1,
|
||||
PostViewJsonV400(view_id = Constant.SYSTEM_READ_TRANSACTIONS_BERLIN_GROUP_VIEW_ID, is_system = true)
|
||||
)
|
||||
val requestGet = (V1_3_BG / "accounts" / testAccountId.value / "transactions").GET <@ (user1)
|
||||
val requestGet = (V1_3_BG / "accounts" / testAccountId.value / "transactions").GET <@ (user1) <<? List(("bookingStatus", "both"))
|
||||
val response: APIResponse = makeGetRequest(requestGet)
|
||||
|
||||
Then("We should get a 200 ")
|
||||
response.code should equal(200)
|
||||
response.body.extract[TransactionsJsonV13].account.iban should not be ("")
|
||||
response.body.extract[TransactionsJsonV13].transactions.pending.head.length > 0 should be (true)
|
||||
response.body.extract[TransactionsJsonV13].transactions.pending.head.nonEmpty should be (true)
|
||||
// response.body.extract[TransactionsJsonV13].transactions.pending.length > 0 should be (true)
|
||||
val transactionId = response.body.extract[TransactionsJsonV13].transactions.pending.head.head.transactionId
|
||||
|
||||
|
||||
@ -100,10 +100,6 @@ class JSONFactory_BERLIN_GROUP_1_3Test extends FeatureSpec with Matchers with Gi
|
||||
val result = JSONFactory_BERLIN_GROUP_1_3.createTransactionJSON(transaction)
|
||||
|
||||
result.transactionId shouldBe transaction.id.value
|
||||
result.creditorName shouldBe None //Some("Creditor Name")
|
||||
result.creditorAccount shouldBe None
|
||||
result.debtorName shouldBe None//Some(bankAccount.name)
|
||||
result.debtorAccount shouldBe None
|
||||
|
||||
result.transactionAmount.currency shouldBe transaction.currency.get
|
||||
result.bookingDate should not be empty
|
||||
@ -112,8 +108,8 @@ class JSONFactory_BERLIN_GROUP_1_3Test extends FeatureSpec with Matchers with Gi
|
||||
|
||||
val jsonString: String = compactRender(Extraction.decompose(result))
|
||||
|
||||
jsonString.contains("creditorName") shouldBe false
|
||||
jsonString.contains("creditorAccount") shouldBe false
|
||||
jsonString.contains("creditorName") shouldBe true
|
||||
jsonString.contains("creditorAccount") shouldBe true
|
||||
jsonString.contains("debtorName") shouldBe false
|
||||
jsonString.contains("debtorAccount") shouldBe false
|
||||
|
||||
|
||||
85
obp-api/src/test/scala/code/util/PasswordUtilTest.scala
Normal file
85
obp-api/src/test/scala/code/util/PasswordUtilTest.scala
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
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.api.util
|
||||
|
||||
import code.util.Helper.MdcLoggable
|
||||
import org.scalatest.{FeatureSpec, GivenWhenThen, Matchers}
|
||||
|
||||
class PasswordUtilTest extends FeatureSpec with Matchers with GivenWhenThen with MdcLoggable {
|
||||
|
||||
feature("Evaluate password strength using Zxcvbn") {
|
||||
|
||||
scenario("Very weak password should return low score and be unacceptable") {
|
||||
Given("a common password '12345678'")
|
||||
val password = "12345678"
|
||||
|
||||
When("measured with zxcvbn")
|
||||
val strength = PasswordUtil.getStrength(password)
|
||||
|
||||
Then("the score should be 0 and it should be unacceptable")
|
||||
strength.getScore should be <= 1
|
||||
PasswordUtil.isAcceptable(password) should be (false)
|
||||
}
|
||||
|
||||
scenario("Moderate password should be acceptable") {
|
||||
Given("a moderately strong password 'OpenBank2025$'")
|
||||
val password = "OpenBank2025$"
|
||||
|
||||
When("measured with zxcvbn")
|
||||
val strength = PasswordUtil.getStrength(password)
|
||||
|
||||
Then("the score should be >= 3 and it should be acceptable")
|
||||
strength.getScore should be >= 3
|
||||
PasswordUtil.isAcceptable(password) should be (true)
|
||||
}
|
||||
|
||||
scenario("Strong password with emoji and unicode should be acceptable") {
|
||||
Given("a complex password '🔥MySecurę密码2025!'")
|
||||
val password = "🔥MySecurę密码2025!"
|
||||
|
||||
When("measured with zxcvbn")
|
||||
val strength = PasswordUtil.getStrength(password)
|
||||
|
||||
Then("the score should be >= 3 and it should be acceptable")
|
||||
strength.getScore should be >= 3
|
||||
PasswordUtil.isAcceptable(password) should be (true)
|
||||
}
|
||||
|
||||
scenario("Very strong password should be clearly acceptable") {
|
||||
Given("a very strong password 'G@lacticSafe#AlphaZebra99!!'")
|
||||
val password = "G@lacticSafe#AlphaZebra99!!"
|
||||
|
||||
When("measured with zxcvbn")
|
||||
val strength = PasswordUtil.getStrength(password)
|
||||
|
||||
Then("the score should be 4 and it should be acceptable")
|
||||
strength.getScore should be (4)
|
||||
PasswordUtil.isAcceptable(password) should be (true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -173,6 +173,14 @@ object PemCertificateRole extends OBPEnumeration[PemCertificateRole] {
|
||||
object PSP_IC extends Value
|
||||
object PSP_AI extends Value
|
||||
object PSP_PI extends Value
|
||||
|
||||
def toBerlinGroup(role: String): String = {
|
||||
role match {
|
||||
case item if PSP_AI.toString == item => "AISP"
|
||||
case item if PSP_PI.toString == item => "PISP"
|
||||
case _ => ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait UserInvitationPurpose extends EnumValue
|
||||
|
||||
Loading…
Reference in New Issue
Block a user