Merge pull request #670 from constantine2nd/develop

Gateway integration
This commit is contained in:
Simon Redfern 2017-07-21 08:18:12 +02:00 committed by GitHub
commit 48c9910f3d
6 changed files with 129 additions and 34 deletions

View File

@ -28,14 +28,16 @@ package code.api
import authentikat.jwt.{JsonWebToken, JwtClaimsSet, JwtHeader}
import code.api.util.ErrorMessages
import code.model.User
import code.consumer.Consumers
import code.model.{Consumer, User}
import code.users.Users
import code.util.Helper.MdcLoggable
import net.liftweb.common._
import net.liftweb.http._
import net.liftweb.http.rest.RestHelper
import net.liftweb.json._
import net.liftweb.util.Helpers._
import net.liftweb.util.Props
import net.liftweb.util.{Helpers, Props}
/**
* This object provides the API calls necessary to
@ -43,11 +45,38 @@ import net.liftweb.util.Props
*/
object JSONFactoryGateway {
case class TokenJSON(
username: String,
is_first: Option[Boolean],
CBS_auth_token: Option[String],
timestamp: String,
consumer_id: String,
consumer_name: String
)
}
object GatewayLogin extends RestHelper with MdcLoggable {
val gateway = "Gateway" // This value is used for ResourceUser.provider and Consumer.description
def createJwt(payloadAsJsonString: String) : String = {
val jwtJson = parse(payloadAsJsonString) // Transform Json string to JsonAST
val username = compact(render(jwtJson.\\("username"))).replace("\"", "") // Extract value from field username and remove quotation
val consumerId = compact(render(jwtJson.\\("consumer_id"))).replace("\"", "") // Extract value from field username and remove quotation
val consumerName = compact(render(jwtJson.\\("consumer_name"))).replace("\"", "") // Extract value from field username and remove quotation
val isFirst = compact(render(jwtJson.\\("is_first"))).replace("\"", "") // Extract value from field username and remove quotation
val timestamp = compact(render(jwtJson.\\("timestamp"))).replace("\"", "") // Extract value from field username and remove quotation
val json = JSONFactoryGateway.TokenJSON(
username = username,
is_first = None,
CBS_auth_token = None,
timestamp = timestamp,
consumer_id = consumerId,
consumer_name = consumerName
)
val header = JwtHeader("HS256")
val claimsSet = JwtClaimsSet(payloadAsJsonString)
val claimsSet = JwtClaimsSet(compact(render(Extraction.decompose(json))))
val secretKey = Props.get("gateway.token_secret", "Cannot get the secret")
val jwt: String = JsonWebToken(header, claimsSet, secretKey)
jwt
@ -106,11 +135,39 @@ object GatewayLogin extends RestHelper with MdcLoggable {
}
}
def getUser(jwt: String) : Box[User] = {
def getOrCreateResourceUser(jwt: String) : Box[User] = {
val jwtJson = parse(jwt) // Transform Json string to JsonAST
val username = compact(render(jwtJson.\\("username"))).replace("\"", "") // Extract value from field username and remove quotation
logger.debug("username: " + username)
Empty
Users.users.vend.getUserByProviderId(provider = "Gateway", idGivenByProvider = username).or {
Users.users.vend.createResourceUser(
provider = gateway,
providerId = Some(username),
name = Some(username),
email = None,
userId = None
)
}
}
def getOrCreateConsumer(jwt: String, u: User) : Box[Consumer] = {
val jwtJson = parse(jwt) // Transform Json string to JsonAST
val consumerId = compact(render(jwtJson.\\("consumer_id"))).replace("\"", "") // Extract value from field username and remove quotation
logger.debug("consumer_id: " + consumerId)
val consumerName = compact(render(jwtJson.\\("consumer_name"))).replace("\"", "") // Extract value from field username and remove quotation
logger.debug("consumerName: " + consumerName)
Consumers.consumers.vend.getOrCreateConsumer(
consumerId=Some(consumerId),
Some(Helpers.randomString(40).toLowerCase),
Some(Helpers.randomString(40).toLowerCase),
Some(true),
name = Some(consumerName),
appType = None,
description = Some(gateway),
developerEmail = None,
redirectURL = None,
createdByUserId = Some(u.userId)
)
}
// Return a Map containing the GatewayLogin parameter : token -> value

View File

@ -133,14 +133,14 @@ trait OBPRestHelper extends RestHelper with MdcLoggable {
def failIfBadAuthorizationHeader(fn: (Box[User]) => Box[JsonResponse]) : JsonResponse = {
if (hasAnOAuthHeader) {
getUser match {
case Full(u) => fn(Full(u))
case Full(u) => fn(Full(u)) // Authentication is successful
case ParamFailure(_, _, _, apiFailure : APIFailure) => errorJsonResponse(apiFailure.msg, apiFailure.responseCode)
case Failure(msg, _, _) => errorJsonResponse(msg)
case _ => errorJsonResponse("oauth error")
}
} else if (Props.getBool("allow_direct_login", true) && hasDirectLoginHeader) {
DirectLogin.getUser match {
case Full(u) => fn(Full(u))
case Full(u) => fn(Full(u)) // Authentication is successful
case _ => {
var (httpCode, message, directLoginParameters) = DirectLogin.validator("protectedResource", DirectLogin.getHttpMethod)
errorJsonResponse(message, httpCode)
@ -152,11 +152,15 @@ trait OBPRestHelper extends RestHelper with MdcLoggable {
val (httpCode, message, parameters) = GatewayLogin.validator(S.request)
httpCode match {
case 200 =>
val jwt = GatewayLogin.parseJwt(parameters)
GatewayLogin.getUser(jwt: String) match {
case Full(u) => fn(Full(u))
val payload = GatewayLogin.parseJwt(parameters)
GatewayLogin.getOrCreateResourceUser(payload: String) match {
case Full(u) => // Authentication is successful
GatewayLogin.getOrCreateConsumer(payload, u)
val jwtResponse = GatewayLogin.createJwt(payload)
setGatewayResponseHeader(jwtResponse)
fn(Full(u))
case Failure(msg, _, _) => errorJsonResponse(msg)
case _ => errorJsonResponse(jwt, httpCode)
case _ => errorJsonResponse(payload, httpCode)
}
case _ => errorJsonResponse(message, httpCode)
}

View File

@ -24,7 +24,7 @@ trait ConsumersProvider {
def getConsumerByPrimaryId(id: Long): Box[Consumer]
def getConsumerByConsumerKey(consumerKey: String): Box[Consumer]
def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
def updateConsumer(consumerId: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
def updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer]
}
@ -34,7 +34,7 @@ class RemotedataConsumersCaseClasses {
case class getConsumerByPrimaryId(id: Long)
case class getConsumerByConsumerKey(consumerKey: String)
case class createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
case class updateConsumer(consumerId: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
case class updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
case class getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String])
}

View File

@ -116,7 +116,7 @@ object MappedConsumersProvider extends ConsumersProvider {
}
}
override def updateConsumer(consumerId: Long,
override def updateConsumer(id: Long,
key: Option[String],
secret: Option[String],
isActive: Option[Boolean],
@ -126,7 +126,7 @@ object MappedConsumersProvider extends ConsumersProvider {
developerEmail: Option[String],
redirectURL: Option[String],
createdByUserId: Option[String]): Box[Consumer] = {
val consumer = Consumer.find(By(Consumer.id, consumerId))
val consumer = Consumer.find(By(Consumer.id, id))
consumer match {
case Full(c) => tryo {
key match {
@ -181,20 +181,54 @@ object MappedConsumersProvider extends ConsumersProvider {
developerEmail: Option[String],
redirectURL: Option[String],
createdByUserId: Option[String]): Box[Consumer] = {
consumerId match {
case Some(id) =>
Consumer.find(By(Consumer.consumerId, id))
case None =>
createConsumer(key = key,
secret = secret,
isActive = isActive,
name = name,
appType = appType,
description = description,
developerEmail = developerEmail,
redirectURL = redirectURL,
createdByUserId = createdByUserId
)
Consumer.find(By(Consumer.consumerId, consumerId.getOrElse(Helpers.randomString(40)))) match {
case Full(c) => Full(c)
case Empty =>
tryo {
val c = Consumer.create
key match {
case Some(v) => c.key(v)
case None =>
}
secret match {
case Some(v) => c.secret(v)
case None =>
}
isActive match {
case Some(v) => c.isActive(v)
case None =>
}
name match {
case Some(v) => c.name(v)
case None =>
}
appType match {
case Some(v) => c.appType(v)
case None =>
}
description match {
case Some(v) => c.description(v)
case None =>
}
developerEmail match {
case Some(v) => c.developerEmail(v)
case None =>
}
redirectURL match {
case Some(v) => c.redirectURL(v)
case None =>
}
createdByUserId match {
case Some(v) => c.createdByUserId(v)
case None =>
}
consumerId match {
case Some(v) => c.consumerId(v)
case None =>
}
c.saveMe()
}
}
}

View File

@ -47,8 +47,8 @@ object RemotedataConsumers extends ObpActorInit with ConsumersProvider {
def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] =
extractFutureToBox(actor ? cc.createConsumer(key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
def updateConsumer(consumerId: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] =
extractFutureToBox(actor ? cc.updateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
def updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] =
extractFutureToBox(actor ? cc.updateConsumer(id, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] =
extractFutureToBox(actor ? cc.getOrCreateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))

View File

@ -25,9 +25,9 @@ class RemotedataConsumersActor extends Actor with ObpActorHelper with MdcLoggabl
logger.debug("createConsumer(" + "*****" + ", " + "*****" + ", " + isActive.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")
sender ! extractResult(mapper.createConsumer(key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
case cc.updateConsumer(consumerId: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) =>
logger.debug("createConsumer(" + consumerId + ", " + "*****" + ", " + "*****" + ", " + isActive.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")
sender ! extractResult(mapper.updateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
case cc.updateConsumer(id: Long, key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) =>
logger.debug("createConsumer(" + id + ", " + "*****" + ", " + "*****" + ", " + isActive.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")
sender ! extractResult(mapper.updateConsumer(id, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId))
case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType.AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) =>
logger.debug("getOrCreateConsumer(" + consumerId.getOrElse("None") + ", " + "*****" + ", " + "*****" + ", " + isActive.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")")