From 4cc824d059f1306fd26fa2a12bb3d748239ea3d2 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 4 May 2022 12:06:26 +0200 Subject: [PATCH] feature/added attemptCounter field to MappedChallengeProvider table --- .../scala/code/api/util/ErrorMessages.scala | 1 + .../scala/code/api/v2_1_0/APIMethods210.scala | 5 -- .../scala/code/api/v4_0_0/APIMethods400.scala | 5 -- .../MappedChallengeProvider.scala | 46 +++++++++++-------- .../MappedExpectedChallengeAnswer.scala | 4 ++ .../commons/model/CommonModel.scala | 1 + .../commons/model/CommonModelTrait.scala | 2 + 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index 8115a0065..e1a6d412b 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -525,6 +525,7 @@ object ErrorMessages { val InvalidChallengeType = "OBP-40015: Invalid Challenge Type. Please specify a valid value for CHALLENGE_TYPE, when you create the transaction request." val InvalidChallengeAnswer = "OBP-40016: Invalid Challenge Answer. Please specify a valid value for answer in Json body. " + "The challenge answer may be expired." + + "Or you've used up your allowed attempts (3 times)." + "Or if connector = mapped and transactionRequestType_OTP_INSTRUCTION_TRANSPORT = DUMMY and suggested_default_sca_method=DUMMY, the answer must be `123`. " + "Or if connector = others, the challenge answer can be got by phone message or other security ways." val InvalidPhoneNumber = "OBP-40017: Invalid Phone Number. Please specify a valid value for PHONE_NUMBER. Eg:+9722398746 " diff --git a/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala b/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala index 222aa6afc..6a783baaa 100644 --- a/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala +++ b/obp-api/src/main/scala/code/api/v2_1_0/APIMethods210.scala @@ -637,11 +637,6 @@ trait APIMethods210 { existingTransactionRequest.challenge.id.equals(challengeAnswerJson.id) } - //Check the allowed attempts, Note: not support yet, the default value is 3 - _ <- Helper.booleanToFuture(s"${AllowedAttemptsUsedUp}", cc=callContext) { - existingTransactionRequest.challenge.allowed_attempts > 0 - } - //Check the challenge type, Note: not support yet, the default value is SANDBOX_TAN _ <- Helper.booleanToFuture(s"${InvalidChallengeType} ", cc=callContext) { existingTransactionRequest.challenge.challenge_type == TransactionChallengeTypes.OTP_VIA_API.toString diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 25e006305..3cd1f87c9 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -1363,11 +1363,6 @@ trait APIMethods400 { existingTransactionRequestType.equals(transactionRequestType.value) } - //Check the allowed attempts, Note: not supported yet, the default value is 3 - _ <- Helper.booleanToFuture(s"${AllowedAttemptsUsedUp}", cc=callContext) { - existingTransactionRequest.challenge.allowed_attempts > 0 - } - //Check the challenge type, Note: not supported yet, the default value is SANDBOX_TAN _ <- Helper.booleanToFuture(s"${InvalidChallengeType} ", cc=callContext) { List( diff --git a/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala b/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala index e3961d84e..4d666bbb2 100644 --- a/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala +++ b/obp-api/src/main/scala/code/transactionChallenge/MappedChallengeProvider.scala @@ -58,32 +58,40 @@ object MappedChallengeProvider extends ChallengeProvider { ): Box[ChallengeTrait] = { val challenge = getChallenge(challengeId).openOrThrowException(s"${ErrorMessages.InvalidChallengeAnswer}") + val currentAttemptCounterValue = challenge.attemptCounter + //We update the counter anyway. + challenge.mAttemptCounter(currentAttemptCounterValue+1).saveMe() + val createDate = challenge.createdAt.get val tokenDuration : Long = Helpers.seconds(APIUtil.otpExpirationSeconds) val expiredDateTime: Long = createDate.getTime+tokenDuration val currentTime: Long = Platform.currentTime - if(expiredDateTime > currentTime) { - val currentHashedAnswer = BCrypt.hashpw(challengeAnswer, challenge.salt).substring(0, 44) - val expectedHashedAnswer = challenge.expectedAnswer - - userId match { - case None => - if(currentHashedAnswer==expectedHashedAnswer) { - tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()} - } else { - Failure(s"${ErrorMessages.InvalidChallengeAnswer}") - } - case Some(id) => - if(currentHashedAnswer==expectedHashedAnswer && id==challenge.expectedUserId) { - tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()} - } else { - Failure(s"${ErrorMessages.InvalidChallengeAnswer}") - } + if(currentAttemptCounterValue <3){ + if(expiredDateTime > currentTime) { + val currentHashedAnswer = BCrypt.hashpw(challengeAnswer, challenge.salt).substring(0, 44) + val expectedHashedAnswer = challenge.expectedAnswer + + userId match { + case None => + if(currentHashedAnswer==expectedHashedAnswer) { + tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()} + } else { + Failure(s"${ErrorMessages.InvalidChallengeAnswer}") + } + case Some(id) => + if(currentHashedAnswer==expectedHashedAnswer && id==challenge.expectedUserId) { + tryo{challenge.mSuccessful(true).mScaStatus(StrongCustomerAuthenticationStatus.finalised.toString).saveMe()} + } else { + Failure(s"${ErrorMessages.InvalidChallengeAnswer}") + } + } + }else{ + Failure(s"${ErrorMessages.OneTimePasswordExpired} Current expiration time is $otpExpirationSeconds seconds") } - }else{ - Failure(s"${ErrorMessages.OneTimePasswordExpired} Current expiration time is $otpExpirationSeconds seconds") + }else{ + Failure(s"${ErrorMessages.AllowedAttemptsUsedUp}") } } } \ No newline at end of file diff --git a/obp-api/src/main/scala/code/transactionChallenge/MappedExpectedChallengeAnswer.scala b/obp-api/src/main/scala/code/transactionChallenge/MappedExpectedChallengeAnswer.scala index 9c8de1984..7a5d810fd 100644 --- a/obp-api/src/main/scala/code/transactionChallenge/MappedExpectedChallengeAnswer.scala +++ b/obp-api/src/main/scala/code/transactionChallenge/MappedExpectedChallengeAnswer.scala @@ -24,6 +24,9 @@ class MappedExpectedChallengeAnswer extends ChallengeTrait with LongKeyedMapper[ object mScaStatus extends MappedString(this,100) object mConsentId extends MappedString(this,100) object mAuthenticationMethodId extends MappedString(this,100) + object mAttemptCounter extends MappedInt(this){ + override def defaultValue = 0 + } override def challengeId: String = mChallengeId.get override def challengeType: String = mChallengeType.get @@ -36,6 +39,7 @@ class MappedExpectedChallengeAnswer extends ChallengeTrait with LongKeyedMapper[ override def scaMethod: Option[SCA] = Option(StrongCustomerAuthentication.withName(mScaMethod.get)) override def scaStatus: Option[SCAStatus] = Option(StrongCustomerAuthenticationStatus.withName(mScaStatus.get)) override def authenticationMethodId: Option[String] = Option(mAuthenticationMethodId.get) + override def attemptCounter: Int = mAttemptCounter.get } object MappedExpectedChallengeAnswer extends MappedExpectedChallengeAnswer with LongKeyedMetaMapper[MappedExpectedChallengeAnswer] { diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala index 4dcc113dc..bab5c55a8 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala @@ -532,6 +532,7 @@ case class ChallengeCommons( override val scaMethod: Option[SCA], override val scaStatus: Option[SCAStatus], override val authenticationMethodId: Option[String] , + override val attemptCounter: Int = 0 ) extends ChallengeTrait object ChallengeCommons extends Converter[ChallengeTrait, ChallengeCommons] diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala index 3628d7ccf..28ad631af 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala @@ -561,6 +561,8 @@ trait ChallengeTrait { def scaMethod: Option[SCA] def scaStatus: Option[SCAStatus] def authenticationMethodId: Option[String] + + def attemptCounter: Int }