Skip to content

Commit

Permalink
Merge pull request #2296 from hongwei1/develop
Browse files Browse the repository at this point in the history
feature/use Twilio as OBP OTP library
  • Loading branch information
simonredfern committed Oct 19, 2023
2 parents 515e681 + 5e18b12 commit 66ff691
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 143 deletions.
7 changes: 4 additions & 3 deletions obp-api/src/main/resources/props/sample.props.template
Original file line number Diff line number Diff line change
Expand Up @@ -887,9 +887,10 @@ database_messages_scheduler_interval=3600
# ---------------------------------------------------------

# -- SCA (Strong Customer Authentication) -------
# For now, OBP-API use `Twilio` server as the SMS provider. Please check `Twilio` website, and get the api key and value there.
# sca_phone_api_key = oXAjqAJ6rvCunpzN
# sca_phone_api_secret =oXAjqAJ6rvCunpzN123sdf
# For now, OBP-API use `Twilio` server as the SMS provider. Please check `Twilio` website, and get the api key, value and phone number there.
# sca_phone_api_key = ACobpb72ab850501b5obp8dobp9dobp111
# sca_phone_api_secret =7afobpdacobpd427obpff87a22obp222
# sca_phone_api_id =MGcobp8575119887f10b62a2461obpb333
#

# -- PSD2 Certificates --------------------------
Expand Down
2 changes: 0 additions & 2 deletions obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ import code.customer.{MappedCustomer, MappedCustomerMessage}
import code.customeraccountlinks.CustomerAccountLink
import code.customeraddress.MappedCustomerAddress
import code.customerattribute.MappedCustomerAttribute
import code.database.authorisation.Authorisation
import code.directdebit.DirectDebit
import code.dynamicEntity.DynamicEntity
import code.dynamicMessageDoc.DynamicMessageDoc
Expand Down Expand Up @@ -1057,7 +1056,6 @@ object ToSchemify {
MethodRouting,
EndpointMapping,
WebUiProps,
Authorisation,
DynamicEntity,
DynamicData,
DynamicEndpoint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import code.api.util.APIUtil._
import code.api.util.{APIUtil, ConsentJWT, CustomJsonFormats, JwtUtil}
import code.bankconnectors.Connector
import code.consent.ConsentTrait
import code.database.authorisation.Authorisation
import code.model.ModeratedTransaction
import com.openbankproject.commons.model.enums.AccountRoutingScheme
import com.openbankproject.commons.model.{BankAccount, TransactionRequest, User, _}
Expand Down
5 changes: 5 additions & 0 deletions obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ trait APIMethods220 {
bank <- tryo{ json.extract[BankJSONV220] } ?~! ErrorMessages.InvalidJsonFormat
_ <- Helper.booleanToBox(
bank.id.length > 5,s"$InvalidJsonFormat Min length of BANK_ID should be 5 characters.")

checkShortStringValue = APIUtil.checkShortString(bank.id)

_ <- Helper.booleanToBox(checkShortStringValue == SILENCE_IS_GOLDEN, s"$checkShortStringValue.")

_ <- Helper.booleanToBox(
!`checkIfContains::::` (bank.id), s"$InvalidJsonFormat BANK_ID can not contain `::::` characters")
u <- cc.user ?~!ErrorMessages.UserNotLoggedIn
Expand Down
8 changes: 7 additions & 1 deletion obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{app
import code.usercustomerlinks.UserCustomerLink
import code.userlocks.UserLocksProvider
import code.users.Users
import code.util.Helper.{ObpS, booleanToFuture}
import code.util.Helper.{ObpS, SILENCE_IS_GOLDEN, booleanToFuture}
import code.util.{Helper, JsonSchemaUtil}
import code.validation.JsonValidation
import code.views.Views
Expand Down Expand Up @@ -4039,6 +4039,12 @@ trait APIMethods400 {
cc.callContext.map(_.consumer.isDefined == true).isDefined
}

checkShortStringValue = APIUtil.checkShortString(bank.id)

_ <- Helper.booleanToFuture(failMsg = s"$checkShortStringValue.", cc=cc.callContext) {
checkShortStringValue==SILENCE_IS_GOLDEN
}

_ <- Helper.booleanToFuture(failMsg = s"$InvalidJsonFormat Min length of BANK_ID should be greater than 3 characters.", cc=cc.callContext) {
bank.id.length > 3
}
Expand Down
9 changes: 8 additions & 1 deletion obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import code.model._
import code.model.dataAccess.BankAccountCreation
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
import code.util.Helper
import code.util.Helper.booleanToFuture
import code.util.Helper.{SILENCE_IS_GOLDEN, booleanToFuture}
import code.views.Views
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.ExecutionContext.Implicits.global
Expand Down Expand Up @@ -183,6 +183,13 @@ trait APIMethods500 {
postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
json.extract[PostBankJson500]
}

//if postJson.id is empty, just return SILENCE_IS_GOLDEN, and will pass the guard.
checkShortStringValue = APIUtil.checkShortString(postJson.id.getOrElse(SILENCE_IS_GOLDEN))
_ <- Helper.booleanToFuture(failMsg = s"$checkShortStringValue.", cc = cc.callContext) {
checkShortStringValue == SILENCE_IS_GOLDEN
}

_ <- Helper.booleanToFuture(failMsg = ErrorMessages.InvalidConsumerCredentials, cc=cc.callContext) {
cc.callContext.map(_.consumer.isDefined == true).isDefined
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import code.customer._
import code.customeraccountlinks.CustomerAccountLinkTrait
import code.customeraddress.CustomerAddressX
import code.customerattribute.CustomerAttributeX
import code.database.authorisation.Authorisations
import code.directdebit.DirectDebits
import code.endpointTag.{EndpointTag, EndpointTagT}
import code.fx.fx.TTL
Expand Down Expand Up @@ -334,14 +333,16 @@ object LocalMappedConnector extends Connector with MdcLoggable {
challengeId.toList
}

Authorisations.authorisationProvider.vend.createAuthorization(
transactionRequestId.getOrElse(""),
consentId.getOrElse(""),
AuthenticationType.SMS_OTP.toString,
"",
ScaStatus.received.toString,
"12345" // TODO Implement SMS sending
)
//We use obp MappedExpectedChallengeAnswer instead of Authorisations now.
// please also check Challenges.ChallengeProvider.vend.saveChallenge
// Authorisations.authorisationProvider.vend.createAuthorization(
// transactionRequestId.getOrElse(""),
// consentId.getOrElse(""),
// AuthenticationType.SMS_OTP.toString,
// "",
// ScaStatus.received.toString,
// "12345" // TODO Implement SMS sending
// )

(Full(challenges.flatten), callContext)
}
Expand Down Expand Up @@ -396,12 +397,25 @@ object LocalMappedConnector extends Connector with MdcLoggable {
for {
smsProviderApiKey <- APIUtil.getPropsValue("sca_phone_api_key") ?~! s"$MissingPropsValueAtThisInstance sca_phone_api_key"
smsProviderApiSecret <- APIUtil.getPropsValue("sca_phone_api_secret") ?~! s"$MissingPropsValueAtThisInstance sca_phone_api_secret"
client = Twilio.init(smsProviderApiKey, smsProviderApiSecret)
scaPhoneApiId <- APIUtil.getPropsValue("sca_phone_api_id") ?~! s"$MissingPropsValueAtThisInstance sca_phone_api_id"
client = Twilio.init(smsProviderApiKey, smsProviderApiSecret) //TODO, move this to other place, we only need to init it once.
phoneNumber = tuple._2
messageText = s"Your consent challenge : ${challengeAnswer}";
message: Box[Message] = tryo(Message.creator(new PhoneNumber(phoneNumber), new PhoneNumber(phoneNumber), messageText).create())
failMsg = s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first. ${message.map(_.getErrorMessage).getOrElse("")}"
_ <- Helper.booleanToBox(message.forall(_.getErrorMessage.isEmpty), failMsg)
message: Message <- tryo {Message.creator(
new PhoneNumber(phoneNumber),
scaPhoneApiId,
messageText).create()}

isSuccess <- tryo {message.getErrorMessage == null}

_ = logger.debug(s"createChallengeInternal.send message to $phoneNumber, detail is $message")

failMsg = if (message.getErrorMessage ==null)
s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first. ${message.getErrorMessage}"
else
s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first."

_ <- Helper.booleanToBox(isSuccess, failMsg)
} yield true
}
val errorMessage = sendingResult.filter(_.isInstanceOf[Failure]).map(_.asInstanceOf[Failure].msg)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package code.database.authorisation

import net.liftweb.common.Box
import net.liftweb.util.SimpleInjector


object Authorisations extends SimpleInjector {
val authorisationProvider = new Inject(buildOne _) {}
def buildOne: AuthorisationProvider = MappedAuthorisationProvider
}

trait AuthorisationProvider {
def getAuthorizationByAuthorizationId(authorizationId: String): Box[Authorisation]
def getAuthorizationByAuthorizationId(paymentId: String, authorizationId: String): Box[Authorisation]
def getAuthorizationByPaymentId(paymentId: String): Box[List[Authorisation]]
def getAuthorizationByConsentId(consentId: String): Box[List[Authorisation]]
def createAuthorization(paymentId: String,
consentId: String,
authenticationType: String,
authenticationMethodId: String,
scaStatus: String,
challengeData: String
): Box[Authorisation]
def checkAnswer(paymentId: String, authorizationId: String, challengeData: String): Box[Authorisation]
}
//package code.database.authorisation
//
//import net.liftweb.common.Box
//import net.liftweb.util.SimpleInjector
//
//
//object Authorisations extends SimpleInjector {
// val authorisationProvider = new Inject(buildOne _) {}
// def buildOne: AuthorisationProvider = MappedAuthorisationProvider
//}
//
//trait AuthorisationProvider {
// def getAuthorizationByAuthorizationId(authorizationId: String): Box[Authorisation]
// def getAuthorizationByAuthorizationId(paymentId: String, authorizationId: String): Box[Authorisation]
// def getAuthorizationByPaymentId(paymentId: String): Box[List[Authorisation]]
// def getAuthorizationByConsentId(consentId: String): Box[List[Authorisation]]
// def createAuthorization(paymentId: String,
// consentId: String,
// authenticationType: String,
// authenticationMethodId: String,
// scaStatus: String,
// challengeData: String
// ): Box[Authorisation]
// def checkAnswer(paymentId: String, authorizationId: String, challengeData: String): Box[Authorisation]
//}
Loading

0 comments on commit 66ff691

Please sign in to comment.