Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
case Some(STATIC) => {
val cacheValueFromRedis = Caching.getStaticResourceDocCache(cacheKey)

val dynamicDocs: Box[JValue] =
val staticDocs: Box[JValue] =
if (cacheValueFromRedis.isDefined) {
Full(json.parse(cacheValueFromRedis.get))
} else {
Expand All @@ -530,12 +530,12 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
Full(resourceDocJsonJValue)
}

Future(dynamicDocs.map(successJsonResponse(_)))
Future(staticDocs.map(successJsonResponse(_)))
}
case _ => {
val cacheValueFromRedis = Caching.getAllResourceDocCache(cacheKey)

val dynamicDocs: Box[JValue] =
val bothStaticAndDyamicDocs: Box[JValue] =
if (cacheValueFromRedis.isDefined) {
Full(json.parse(cacheValueFromRedis.get))
} else {
Expand All @@ -546,7 +546,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
Full(resourceDocJsonJValue)
}

Future(dynamicDocs.map(successJsonResponse(_)))
Future(bothStaticAndDyamicDocs.map(successJsonResponse(_)))
}
}
}
Expand Down Expand Up @@ -715,13 +715,11 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth
swaggerJValue <- NewStyle.function.tryons(s"$UnknownError Can not convert internal swagger file.", 400, cc.callContext) {
val cacheValueFromRedis = Caching.getStaticSwaggerDocCache(cacheKey)

val dynamicDocs: JValue =
if (cacheValueFromRedis.isDefined) {
json.parse(cacheValueFromRedis.get)
} else {
convertResourceDocsToSwaggerJvalueAndSetCache(cacheKey, requestedApiVersionString, resourceDocsJsonFiltered)
}
dynamicDocs
if (cacheValueFromRedis.isDefined) {
json.parse(cacheValueFromRedis.get)
} else {
convertResourceDocsToSwaggerJvalueAndSetCache(cacheKey, requestedApiVersionString, resourceDocsJsonFiltered)
}
}
} yield {
(swaggerJValue, HttpCode.`200`(cc.callContext))
Expand Down
37 changes: 25 additions & 12 deletions obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -784,16 +784,24 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
* (?=.*\d) //should contain at least one digit
* (?=.*[a-z]) //should contain at least one lower case
* (?=.*[A-Z]) //should contain at least one upper case
* (?=.*[!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~]) //should contain at least one special character
* ([A-Za-z0-9!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~]{10,16}) //should contain 10 to 16 valid characters
* (?=.*[!\"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~\[\]]) //should contain at least one special character
* ([A-Za-z0-9!\"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~\[\]]{10,16}) //should contain 10 to 16 valid characters
**/
val regex =
"""^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~])([A-Za-z0-9!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~]{10,16})$""".r
password match {
case password if(password.length > 16 && password.length <= 512 && basicPasswordValidation(password) ==SILENCE_IS_GOLDEN) => true
case regex(password) if(basicPasswordValidation(password) ==SILENCE_IS_GOLDEN) => true
case _ => false
"""^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!\"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~\[\]])([A-Za-z0-9!\"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~\[\]]{10,16})$""".r

// first check `basicPasswordValidation`
if (basicPasswordValidation(password) != SILENCE_IS_GOLDEN) {
return false
}

// 2nd: check the password length between 10 and 512
if (password.length > 16 && password.length <= 512) {
return true
}

// 3rd: check the regular expression
regex.pattern.matcher(password).matches()
}

/** only A-Z, a-z, 0-9,-,_,. =, & and max length <= 2048 */
Expand Down Expand Up @@ -847,12 +855,17 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
/** also support space now */
def basicPasswordValidation(value:String): String ={
val valueLength = value.length
val regex = """^([A-Za-z0-9!"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~ ]+)$""".r
value match {
case regex(e) if(valueLength <= 512) => SILENCE_IS_GOLDEN
case regex(e) if(valueLength > 512) => ErrorMessages.InvalidValueLength
case _ => ErrorMessages.InvalidValueCharacters
val regex = """^([A-Za-z0-9!\"#$%&'\(\)*+,-./:;<=>?@\\[\\\\]^_\\`{|}~ \[\]]+)$""".r

if (!regex.pattern.matcher(value).matches()) {
return ErrorMessages.InvalidValueCharacters
}

if (valueLength > 512) {
return ErrorMessages.InvalidValueLength
}

SILENCE_IS_GOLDEN
}

/** only A-Z, a-z, 0-9, -, _, ., @, and max length <= 512 */
Expand Down
60 changes: 60 additions & 0 deletions obp-api/src/test/scala/code/util/APIUtilTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import code.api.util._
import code.setup.PropsReset
import code.util.Helper.SILENCE_IS_GOLDEN
import com.openbankproject.commons.model.UserAuthContextCommons
import com.github.dwickern.macros.NameOf.nameOf
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.http.provider.HTTPParam
import net.liftweb.json.{JValue, parse}
Expand Down Expand Up @@ -838,6 +839,65 @@ class APIUtilTest extends FeatureSpec with Matchers with GivenWhenThen with Prop
actualValue6 contains (InvalidValueLength) shouldBe (true)

}

scenario(s"Test the ${nameOf(APIUtil.basicPasswordValidation _)} method") {
val firefoxStrongPasswordProposal = "9YF]gZnXzAENM+]"

basicPasswordValidation(firefoxStrongPasswordProposal) shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("Abc!123 xyz") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("SuperStrong#123") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("Hello World!") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation(" ") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN allow space so far

basicPasswordValidation("short💥") shouldBe (InvalidValueCharacters) // ❌ ErrorMessages.InvalidValueCharacters
basicPasswordValidation("a" * 513) shouldBe (InvalidValueLength) // ❌ ErrorMessages.InvalidValueLength

}

scenario(s"Test the ${nameOf(APIUtil.fullPasswordValidation _)} method") {
val firefoxStrongPasswordProposal = "9YF]gZnXzAENM+]"

fullPasswordValidation(firefoxStrongPasswordProposal) // ✅ true
fullPasswordValidation("Abc!123xyz") // ✅ true
fullPasswordValidation("SuperStrong#123") // ✅ true
fullPasswordValidation("Abcdefg!1") // ✅ true
fullPasswordValidation("short1!") // ❌ false(too short)
fullPasswordValidation("alllowercase123!") // ❌ false(no capital letter)
fullPasswordValidation("ALLUPPERCASE123!") // ❌ false(no smaller case letter)
fullPasswordValidation("NoSpecialChar123") // ❌ false(not special character)

}

}

feature(s"test ${nameOf(APIUtil.basicPasswordValidation _)} and ${nameOf(APIUtil.fullPasswordValidation _)}") {

scenario(s"Test the ${nameOf(APIUtil.basicPasswordValidation _)} method") {
val firefoxStrongPasswordProposal = "9YF]gZnXzAENM+]"

basicPasswordValidation(firefoxStrongPasswordProposal) shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("Abc!123 xyz") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("SuperStrong#123") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation("Hello World!") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN
basicPasswordValidation(" ") shouldBe (SILENCE_IS_GOLDEN) // ✅ SILENCE_IS_GOLDEN allow space so far

basicPasswordValidation("short💥") shouldBe (InvalidValueCharacters) // ❌ ErrorMessages.InvalidValueCharacters
basicPasswordValidation("a" * 513) shouldBe (InvalidValueLength) // ❌ ErrorMessages.InvalidValueLength

}

scenario(s"Test the ${nameOf(APIUtil.fullPasswordValidation _)} method") {
val firefoxStrongPasswordProposal = "9YF]gZnXzAENM+]"

fullPasswordValidation(firefoxStrongPasswordProposal) // ✅ true
fullPasswordValidation("Abc!123xyz") // ✅ true
fullPasswordValidation("SuperStrong#123") // ✅ true
fullPasswordValidation("Abcdefg!1") // ✅ true
fullPasswordValidation("short1!") // ❌ false(too short)
fullPasswordValidation("alllowercase123!") // ❌ false(no capital letter)
fullPasswordValidation("ALLUPPERCASE123!") // ❌ false(no smaller case letter)
fullPasswordValidation("NoSpecialChar123") // ❌ false(not special character)
}

}

Expand Down