From fcea29261df5749c8bc0916199c0bea6e02fc26b Mon Sep 17 00:00:00 2001 From: shuang Date: Fri, 27 Sep 2019 20:59:17 +0800 Subject: [PATCH] create direct login tokens for dummy customers --- .../resources/props/sample.props.template | 3 + .../main/scala/code/api/OBPRestHelper.scala | 2 +- .../src/main/scala/code/api/directlogin.scala | 92 ++++++++++--------- .../code/snippet/ConsumerRegistration.scala | 34 ++++++- .../main/webapp/consumer-registration.html | 6 +- 5 files changed, 92 insertions(+), 45 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index 3f9b3c274..40f3d3acb 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -423,6 +423,9 @@ webui_dummy_customer_logins = Customer Logins\ \ Please ask a member of the Open Bank Project team for more logins if you require. You can use this [application](https://sofit.openbankproject.com) which also uses OAuth to browse your transaction data (use the above username/password).\ +# when this value is set to true and webui_dummy_customer_logins value not empty, the register consumer key success page will show dummy customers Direct Login tokens. +webui_show_dummy_customer_tokens=false + # when developer register the consumer successfully, it will show this message to developer on the webpage or email. webui_register_consumer_success_message_webpage = Thanks for registering your consumer with the Open Bank Project API! Here is your developer information. Please save it in a secure location. webui_register_consumer_success_message_email = Thank you for registering to use the Open Bank Project API. diff --git a/obp-api/src/main/scala/code/api/OBPRestHelper.scala b/obp-api/src/main/scala/code/api/OBPRestHelper.scala index 315791323..5dbec0c0f 100644 --- a/obp-api/src/main/scala/code/api/OBPRestHelper.scala +++ b/obp-api/src/main/scala/code/api/OBPRestHelper.scala @@ -266,7 +266,7 @@ trait OBPRestHelper extends RestHelper with MdcLoggable { fn(cc.copy(user = Full(u), consumer=consumer)) }// Authentication is successful case _ => { - var (httpCode, message, directLoginParameters) = DirectLogin.validator("protectedResource", DirectLogin.getHttpMethod) + var (httpCode, message, directLoginParameters) = DirectLogin.validator("protectedResource") Full(errorJsonResponse(message, httpCode)) } } diff --git a/obp-api/src/main/scala/code/api/directlogin.scala b/obp-api/src/main/scala/code/api/directlogin.scala index 645702fa7..834aa58ad 100644 --- a/obp-api/src/main/scala/code/api/directlogin.scala +++ b/obp-api/src/main/scala/code/api/directlogin.scala @@ -94,36 +94,7 @@ object DirectLogin extends RestHelper with MdcLoggable { //Handling get request for a token case Req("my" :: "logins" :: "direct" :: Nil,_ , PostRequest) => { - //Extract the directLogin parameters from the header and test if the request is valid - var (httpCode, message, directLoginParameters) = validator("authorizationToken", getHttpMethod) - - if (httpCode == 200) { - val userId:Long = (for {id <- getUserId(directLoginParameters)} yield id).getOrElse(0) - - if (userId == 0) { - message = ErrorMessages.InvalidLoginCredentials - httpCode = 401 - } else if (userId == AuthUser.usernameLockedStateCode) { - message = ErrorMessages.UsernameHasBeenLocked - httpCode = 401 - } else { - val jwtPayloadAsJson = - """{ - "":"" - }""" - - val jwtClaims: JWTClaimsSet = JWTClaimsSet.parse(jwtPayloadAsJson) - val (token:String, secret:String) = generateTokenAndSecret(jwtClaims) - - //Save the token that we have generated - if (saveAuthorizationToken(directLoginParameters, token, secret, userId)) { - message = token - } else { - httpCode = 500 - message = "invalid" - } - } - } + val (httpCode: Int, message: String) = createToken(getAllParameters) if (httpCode == 200) successJsonResponse(Extraction.decompose(JSONFactory.createTokenJSON(message)), 201) @@ -132,6 +103,45 @@ object DirectLogin extends RestHelper with MdcLoggable { } } + /** + * according username, password, consumer_key to generate a DirectLogin token + * @param allParameters map {"username": "some_username", "password": "some_password", "consumer_key": "some_consumer_key"} + * @return httpCode and token value + */ + def createToken(allParameters: Map[String, String]) = { + //Extract the directLogin parameters from the header and test if the request is valid + var (httpCode, message, directLoginParameters) = validator("authorizationToken", allParameters) + + if (httpCode == 200) { + val userId: Long = (for {id <- getUserId(directLoginParameters)} yield id).getOrElse(0) + + if (userId == 0) { + message = ErrorMessages.InvalidLoginCredentials + httpCode = 401 + } else if (userId == AuthUser.usernameLockedStateCode) { + message = ErrorMessages.UsernameHasBeenLocked + httpCode = 401 + } else { + val jwtPayloadAsJson = + """{ + "":"" + }""" + + val jwtClaims: JWTClaimsSet = JWTClaimsSet.parse(jwtPayloadAsJson) + val (token: String, secret: String) = generateTokenAndSecret(jwtClaims) + + //Save the token that we have generated + if (saveAuthorizationToken(directLoginParameters, token, secret, userId)) { + message = token + } else { + httpCode = 500 + message = "invalid" + } + } + } + (httpCode, message) + } + def getHttpMethod = S.request match { case Full(s) => s.post_? match { case true => "POST" @@ -217,7 +227,7 @@ object DirectLogin extends RestHelper with MdcLoggable { //Check if the request (access token or request token) is valid and return a tuple - def validator(requestType : String, httpMethod : String) : (Int, String, Map[String,String]) = { + def validator(requestType : String, allParameters: Map[String, String] = getAllParameters) : (Int, String, Map[String,String]) = { def validAccessToken(tokenKey: String) = { Tokens.tokens.vend.getTokenByKeyAndType(tokenKey, TokenType.Access) match { @@ -229,12 +239,10 @@ object DirectLogin extends RestHelper with MdcLoggable { var message = "" var httpCode: Int = 500 - val parameters = getAllParameters - //are all the necessary directLogin parameters present? - val missingParams = missingDirectLoginParameters(parameters, requestType) + val missingParams = missingDirectLoginParameters(allParameters, requestType) //guard maximum length and content of strings (a-z, 0-9 etc.) for parameters - val validParams = validDirectLoginParameters(parameters) + val validParams = validDirectLoginParameters(allParameters) if (missingParams.nonEmpty) { message = ErrorMessages.DirectLoginMissingParameters + missingParams.mkString(", ") @@ -246,18 +254,18 @@ object DirectLogin extends RestHelper with MdcLoggable { } else if ( requestType == "protectedResource" && - ! validAccessToken(parameters.getOrElse("token", "")) + ! validAccessToken(allParameters.getOrElse("token", "")) ) { - message = ErrorMessages.DirectLoginInvalidToken + parameters.getOrElse("token", "") + message = ErrorMessages.DirectLoginInvalidToken + allParameters.getOrElse("token", "") httpCode = 401 } //check if the application is registered and active else if ( requestType == "authorizationToken" && APIUtil.getPropsAsBoolValue("direct_login_consumer_key_mandatory", true) && - ! APIUtil.registeredApplication(parameters.getOrElse("consumer_key", ""))) { + ! APIUtil.registeredApplication(allParameters.getOrElse("consumer_key", ""))) { - logger.error("application: " + parameters.getOrElse("consumer_key", "") + " not found") + logger.error("application: " + allParameters.getOrElse("consumer_key", "") + " not found") message = ErrorMessages.InvalidConsumerKey httpCode = 401 } @@ -265,7 +273,7 @@ object DirectLogin extends RestHelper with MdcLoggable { httpCode = 200 if(message.nonEmpty) logger.error("error message : " + message) - (httpCode, message, parameters) + (httpCode, message, allParameters) } @@ -377,7 +385,7 @@ object DirectLogin extends RestHelper with MdcLoggable { case Full(r) => r.request.method case _ => "GET" } - val (httpCode, message, directLoginParameters) = validator("protectedResource", httpMethod) + val (httpCode, message, directLoginParameters) = validator("protectedResource") if (httpCode == 400 || httpCode == 401) ParamFailure(message, Empty, Empty, APIFailure(message, httpCode)) @@ -450,7 +458,7 @@ object DirectLogin extends RestHelper with MdcLoggable { case _ => "GET" } - val (httpCode, message, directLoginParameters) = validator("protectedResource", httpMethod) + val (httpCode, message, directLoginParameters) = validator("protectedResource") val consumer: Option[Consumer] = for { tokenId: String <- directLoginParameters.get("token") diff --git a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala index 282a247aa..c849af3e0 100644 --- a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala +++ b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala @@ -26,6 +26,7 @@ TESOBE (http://www.tesobe.com/) */ package code.snippet +import code.api.DirectLogin import code.api.util.{APIUtil, ErrorMessages} import code.consumer.Consumers import code.model._ @@ -37,6 +38,8 @@ import net.liftweb.util.Helpers._ import net.liftweb.util.{FieldError, Helpers} import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue +import scala.collection.mutable.ListBuffer + class ConsumerRegistration extends MdcLoggable { private object nameVar extends RequestVar("") @@ -89,6 +92,29 @@ class ConsumerRegistration extends MdcLoggable { val urlOAuthEndpoint = APIUtil.getPropsValue("hostname", "") + "/oauth/initiate" val urlDirectLoginEndpoint = APIUtil.getPropsValue("hostname", "") + "/my/logins/direct" val createDirectLoginToken = getWebUiPropsValue("webui_create_directlogin_token_url", "") + val dummyCustomersInfo = getWebUiPropsValue("webui_dummy_customer_logins", "") + val isShowDummyCustomerTokens = getWebUiPropsValue("webui_show_dummy_customer_tokens", "false").toBoolean + val dummyUsersTokens: String = (isShowDummyCustomerTokens, dummyCustomersInfo) match { + case(true, v) if v.nonEmpty => { + val regex = """\{"user_name"\s*:\s*"(.+?)".+?"password"\s*:\s*"(.+?)".+?\}""".r + val matcher = regex.pattern.matcher(v) + val tokens = ListBuffer[String]() + while(matcher.find()) { + val userName = matcher.group(1) + val password = matcher.group(2) + val consumerKey = consumer.key.get + val (code, token) = DirectLogin.createToken(Map(("username", userName), ("password", password), ("consumer_key", consumerKey))) + val authHeader = code match { + case 200 => s"""$userName auth header --> Authorization: DirectLogin token="$token"""" + case _ => s"""$userName - -> username or password is invalid, generate token fail""" + } + tokens += authHeader + } + tokens.mkString(""" | """) + } + case _ => "" + } + val registerConsumerSuccessMessageWebpage = getWebUiPropsValue( "webui_register_consumer_success_message_webpage", "Thanks for registering your consumer with the Open Bank Project API! Here is your developer information. Please save it in a secure location.") @@ -111,7 +137,13 @@ class ConsumerRegistration extends MdcLoggable { "#directlogin-endpoint a [href]" #> urlDirectLoginEndpoint & "#post-consumer-registration-more-info-link a *" #> registrationMoreInfoText & "#post-consumer-registration-more-info-link a [href]" #> registrationMoreInfoUrl & - "#register-consumer-input" #> "" + "#register-consumer-input" #> "" & { + if(dummyUsersTokens.isEmpty) { + ".preparedTokens" #> dummyUsersTokens + } else { + "#preparedTokens *" #> dummyUsersTokens + } + } } def showRegistrationResults(result : Consumer) = { diff --git a/obp-api/src/main/webapp/consumer-registration.html b/obp-api/src/main/webapp/consumer-registration.html index 236cade8a..31d48a41d 100644 --- a/obp-api/src/main/webapp/consumer-registration.html +++ b/obp-api/src/main/webapp/consumer-registration.html @@ -134,10 +134,14 @@ Berlin 13359, Germany
Direct Login Endpoint
endpoint
+
+
Prepared user tokens
+
+
Direct Login Documentation
+