mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 16:56:56 +00:00
feature/added the emailToSpaceMapping and grantEntitlementsToUseDynamicEndpointsAtOneBank methods
This commit is contained in:
parent
d6a44e9ef4
commit
0b08199b73
@ -29,11 +29,12 @@ package code.api
|
||||
import java.util.Date
|
||||
|
||||
import code.api.util.APIUtil._
|
||||
import code.api.util.ErrorMessages.InvalidDirectLoginParameters
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.api.util._
|
||||
import code.consumer.Consumers._
|
||||
import code.model.dataAccess.AuthUser
|
||||
import code.model.{Consumer, Token, TokenType}
|
||||
import code.model.{Consumer, Token, TokenType, UserX}
|
||||
import code.token.Tokens
|
||||
import code.util.Helper.{MdcLoggable, SILENCE_IS_GOLDEN}
|
||||
import com.nimbusds.jwt.JWTClaimsSet
|
||||
@ -43,6 +44,7 @@ import net.liftweb.common._
|
||||
import net.liftweb.http._
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.util.Helpers
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
|
||||
import scala.compat.Platform
|
||||
import scala.concurrent.Future
|
||||
@ -93,9 +95,21 @@ object DirectLogin extends RestHelper with MdcLoggable {
|
||||
{
|
||||
//Handling get request for a token
|
||||
case Req("my" :: "logins" :: "direct" :: Nil,_ , PostRequest) => {
|
||||
for(
|
||||
(httpCode: Int, message: String) <- createTokenFuture(getAllParameters)
|
||||
) yield {
|
||||
for{
|
||||
(httpCode: Int, message: String, userId:Long) <- createTokenFuture(getAllParameters)
|
||||
_ <- if(!emailToSpaceMapping.isEmpty){
|
||||
for{
|
||||
resourceUser <- Future {UserX.findByResourceUserId(userId).openOrThrowException(s"$InvalidDirectLoginParameters can not find the resourceUser!")}
|
||||
authUser <- Future { AuthUser.findUserByUsernameLocally(resourceUser.name).openOrThrowException(s"$InvalidDirectLoginParameters can not find the auth user!")}
|
||||
_ <- Future {tryo{AuthUser.grantEntitlementsToUseDynamicEndpointsAtOneBank(authUser, None)}
|
||||
.openOr(logger.error(s"$authUser.directLogin.grantEntitlementsToUseDynamicEndpointsAtOneBank throw exception!"))}
|
||||
} yield{
|
||||
""
|
||||
}
|
||||
} else{
|
||||
Future.successful("")
|
||||
}
|
||||
} yield {
|
||||
if (httpCode == 200) {
|
||||
(JSONFactory.createTokenJSON(message), HttpCode.`201`(CallContext()))
|
||||
} else {
|
||||
@ -110,7 +124,7 @@ object DirectLogin extends RestHelper with MdcLoggable {
|
||||
* @param allParameters map {"username": "some_username", "password": "some_password", "consumer_key": "some_consumer_key"}
|
||||
* @return httpCode and token value
|
||||
*/
|
||||
def createTokenFuture(allParameters: Map[String, String]): Future[(Int, String)] = {
|
||||
def createTokenFuture(allParameters: Map[String, String]): Future[(Int, String, Long)] = {
|
||||
val httpMethod = S.request match {
|
||||
case Full(r) => r.request.method
|
||||
case _ => "GET"
|
||||
@ -134,12 +148,11 @@ object DirectLogin extends RestHelper with MdcLoggable {
|
||||
createTokenCommonPart(httpCode, message, directLoginParameters)
|
||||
}
|
||||
|
||||
def createTokenCommonPart(code: Int, msg: String, directLoginParameters: Map[String, String]): (Int, String) = {
|
||||
def createTokenCommonPart(code: Int, msg: String, directLoginParameters: Map[String, String]): (Int, String, Long) = {
|
||||
var message = msg
|
||||
var httpCode = code
|
||||
val userId: Long = (for {id <- getUserId(directLoginParameters)} yield id).getOrElse(0)
|
||||
if (httpCode == 200) {
|
||||
val userId: Long = (for {id <- getUserId(directLoginParameters)} yield id).getOrElse(0)
|
||||
|
||||
if (userId == 0) {
|
||||
message = ErrorMessages.InvalidLoginCredentials
|
||||
httpCode = 401
|
||||
@ -164,7 +177,7 @@ object DirectLogin extends RestHelper with MdcLoggable {
|
||||
}
|
||||
}
|
||||
}
|
||||
(httpCode, message)
|
||||
(httpCode, message, userId)
|
||||
}
|
||||
|
||||
def getHttpMethod = S.request match {
|
||||
|
||||
@ -523,6 +523,11 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
def getHeaders() = getHeadersCommonPart() ::: getGatewayResponseHeader()
|
||||
|
||||
case class CustomResponseHeaders(list: List[(String, String)])
|
||||
//This is used for get the value from props `email_to_space_mapping`
|
||||
case class EmailToSpaceMapping(
|
||||
domain: String,
|
||||
bank_ids: List[String]
|
||||
)
|
||||
|
||||
//Note: changed noContent--> defaultSuccess, because of the Swagger format. (Not support empty in DataType, maybe fix it latter.)
|
||||
def noContentJsonResponse(implicit headers: CustomResponseHeaders = CustomResponseHeaders(Nil)) : JsonResponse =
|
||||
@ -2836,6 +2841,10 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
)
|
||||
} map {
|
||||
x =>
|
||||
//TODO due to performance issue, first comment this out,
|
||||
// val authUser = AuthUser.findUserByUsernameLocally(x._1.head.name).openOrThrowException("")
|
||||
// tryo{AuthUser.grantEntitlementsToUseDynamicEndpointsAtOneBank(authUser, x._2)}.openOr(logger.error(s"${x._1} authenticatedAccess.grantEntitlementsToUseDynamicEndpointsAtOneBank throw exception! "))
|
||||
|
||||
// make sure, if `refreshUserIfRequired` throw exception, do not break the `authenticatedAccess`,
|
||||
// TODO better move `refreshUserIfRequired` to other place.
|
||||
tryo{refreshUserIfRequired(x._1,x._2)}.openOr(logger.error(s"${x._1} authenticatedAccess.refreshUserIfRequired throw exception! "))
|
||||
@ -3983,4 +3992,11 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
val berlinGroupV13AliasPath = APIUtil.getPropsValue("berlin_group_v1.3_alias.path","").split("/").toList.map(_.trim)
|
||||
|
||||
val getAtmsIsPublic = APIUtil.getPropsAsBoolValue("apiOptions.getAtmsIsPublic", true)
|
||||
|
||||
def emailToSpaceMapping = {
|
||||
//TODO, error handling,
|
||||
val emailToSpaceMapping = APIUtil.getPropsValue("email_to_space_mapping")
|
||||
val emailToSpaceMappingJson = emailToSpaceMapping.map(json.parse(_))
|
||||
emailToSpaceMappingJson.map(_.extractOrElse[List[EmailToSpaceMapping]](Nil)).getOrElse(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +85,13 @@ object DynamicEndpointHelper extends RestHelper {
|
||||
roles
|
||||
}
|
||||
|
||||
def listOfRolesToUseAllDynamicEndpointsAOneBank(bankId: Option[String]): List[ApiRole] = {
|
||||
val foundInfos: List[DynamicEndpointInfo] = DynamicEndpointProvider.connectorMethodProvider.vend.getAll(bankId)
|
||||
.map(dynamicEndpoint => buildDynamicEndpointInfo(dynamicEndpoint.swaggerString, dynamicEndpoint.dynamicEndpointId.get, dynamicEndpoint.bankId))
|
||||
|
||||
foundInfos.map(getRoles(_)).flatten.toSet.toList
|
||||
}
|
||||
|
||||
def getRoles(dynamicEndpointInfo: DynamicEndpointInfo): List[ApiRole] =
|
||||
for {
|
||||
resourceDoc <- dynamicEndpointInfo.resourceDocs.toList
|
||||
|
||||
@ -30,7 +30,7 @@ trait EntitlementProvider {
|
||||
def getEntitlementsByRole(roleName: String): Box[List[Entitlement]]
|
||||
def getEntitlementsFuture() : Future[Box[List[Entitlement]]]
|
||||
def getEntitlementsByRoleFuture(roleName: String) : Future[Box[List[Entitlement]]]
|
||||
def addEntitlement(bankId: String, userId: String, roleName: String) : Box[Entitlement]
|
||||
def addEntitlement(bankId: String, userId: String, roleName: String, createdByProcess: String="manual") : Box[Entitlement]
|
||||
def deleteDynamicEntityEntitlement(entityName: String, bankId:Option[String]) : Box[Boolean]
|
||||
def deleteEntitlements(entityNames: List[String]) : Box[Boolean]
|
||||
}
|
||||
@ -40,6 +40,7 @@ trait Entitlement {
|
||||
def bankId : String
|
||||
def userId : String
|
||||
def roleName : String
|
||||
def createdByProcess : String
|
||||
}
|
||||
|
||||
class RemotedataEntitlementsCaseClasses {
|
||||
@ -53,7 +54,7 @@ class RemotedataEntitlementsCaseClasses {
|
||||
case class getEntitlementsByRole(roleName: String)
|
||||
case class getEntitlementsFuture()
|
||||
case class getEntitlementsByRoleFuture(roleName: String)
|
||||
case class addEntitlement(bankId: String, userId: String, roleName: String)
|
||||
case class addEntitlement(bankId: String, userId: String, roleName: String, createdByProcess: String="manual")
|
||||
case class deleteDynamicEntityEntitlement(entityName: String, bankId:Option[String])
|
||||
case class deleteEntitlements(entityNames: List[String])
|
||||
}
|
||||
|
||||
@ -102,12 +102,13 @@ object MappedEntitlementsProvider extends EntitlementProvider {
|
||||
}
|
||||
}
|
||||
|
||||
override def addEntitlement(bankId: String, userId: String, roleName: String): Box[Entitlement] = {
|
||||
override def addEntitlement(bankId: String, userId: String, roleName: String, createdByProcess: String ="manual"): Box[Entitlement] = {
|
||||
// Return a Box so we can handle errors later.
|
||||
val addEntitlement = MappedEntitlement.create
|
||||
.mBankId(bankId)
|
||||
.mUserId(userId)
|
||||
.mRoleName(roleName)
|
||||
.mCreatedByProcess(createdByProcess)
|
||||
.saveMe()
|
||||
Some(addEntitlement)
|
||||
}
|
||||
@ -122,11 +123,14 @@ class MappedEntitlement extends Entitlement
|
||||
object mBankId extends UUIDString(this)
|
||||
object mUserId extends UUIDString(this)
|
||||
object mRoleName extends MappedString(this, 64)
|
||||
object mCreatedByProcess extends MappedString(this, 255)
|
||||
|
||||
override def entitlementId: String = mEntitlementId.get.toString
|
||||
override def bankId: String = mBankId.get
|
||||
override def userId: String = mUserId.get
|
||||
override def roleName: String = mRoleName.get
|
||||
override def createdByProcess: String =
|
||||
if(mCreatedByProcess.get == null || mCreatedByProcess.get.isEmpty) "manual" else mCreatedByProcess.get
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -31,9 +31,11 @@ import code.accountholders.AccountHolders
|
||||
import code.api.util.APIUtil.{hasAnOAuthHeader, isValidStrongPassword, logger, _}
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util._
|
||||
import code.api.v4_0_0.dynamic.DynamicEndpointHelper
|
||||
import code.api.{APIFailure, DirectLogin, GatewayLogin, OAuthHandshake}
|
||||
import code.bankconnectors.Connector
|
||||
import code.context.UserAuthContextProvider
|
||||
import code.entitlement.Entitlement
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.users.Users
|
||||
import code.util.Helper
|
||||
@ -926,6 +928,10 @@ def restoreSomeSessions(): Unit = {
|
||||
logUserIn(user, () => {
|
||||
S.notice(S.?("logged.in"))
|
||||
preLoginState()
|
||||
if(!emailToSpaceMapping.isEmpty){
|
||||
tryo{AuthUser.grantEntitlementsToUseDynamicEndpointsAtOneBank(user, None)}
|
||||
.openOr(logger.error(s"${user} authenticatedAccess.grantEntitlementsToUseDynamicEndpointsAtOneBank throw exception! "))
|
||||
}
|
||||
S.redirectTo(redirect)
|
||||
})
|
||||
} else {
|
||||
@ -1104,6 +1110,39 @@ def restoreSomeSessions(): Unit = {
|
||||
} yield v
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spaces is the obp BankIds, each bank can create many dynamice endpoints, all of them are belong to one Bank.(Space)
|
||||
* @param emailToSpaceMappings
|
||||
* @return
|
||||
*/
|
||||
def mySpaces(user: AuthUser, emailToSpaceMappings: List[EmailToSpaceMapping]): List[BankId] ={
|
||||
//1st: first check the user is validated
|
||||
if (user.validated_?) {
|
||||
//userEmail = robert.uk.29@example.com
|
||||
// 2st get the email domain - `example.com`
|
||||
val emailDomain = user.email.get.split("@").last
|
||||
|
||||
//3 return the bankIds
|
||||
emailToSpaceMappings.find(_.domain==emailDomain).map(_.bank_ids).getOrElse(Nil).map(BankId(_))
|
||||
} else {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
def grantEntitlementsToUseDynamicEndpointsAtOneBank(user: AuthUser, callContext: Option[CallContext]) = {
|
||||
val userId = user.user.obj.map(_.userId).getOrElse("")
|
||||
//call mySpaces --> get BankIds --> listOfRolesToUseAllDynamicEndpointsAOneBank (at each bank)--> Grant roles (for each role)
|
||||
for{
|
||||
bankId <- mySpaces(user: AuthUser, emailToSpaceMapping)
|
||||
role <- DynamicEndpointHelper.listOfRolesToUseAllDynamicEndpointsAOneBank(Some(bankId.value))
|
||||
}yield{
|
||||
//TODO, later we can add a diff here: we need create new roles, and remove the out of date ones.
|
||||
if (!hasEntitlement(bankId.value, userId, role)) {
|
||||
Entitlement.entitlement.vend.addEntitlement(bankId.value, userId, role.toString,"grantEntitlementsToUseDynamicEndpointsAtOneBank")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper method
|
||||
|
||||
@ -48,8 +48,8 @@ object RemotedataEntitlements extends ObpActorInit with EntitlementProvider {
|
||||
def getEntitlementsByRoleFuture(roleName: String) : Future[Box[List[Entitlement]]] =
|
||||
(actor ? cc.getEntitlementsByRoleFuture(roleName)).mapTo[Box[List[Entitlement]]]
|
||||
|
||||
def addEntitlement(bankId: String, userId: String, roleName: String) : Box[Entitlement] = getValueFromFuture(
|
||||
(actor ? cc.addEntitlement(bankId, userId, roleName)).mapTo[Box[Entitlement]]
|
||||
def addEntitlement(bankId: String, userId: String, roleName: String, createdByProcess: String="manual") : Box[Entitlement] = getValueFromFuture(
|
||||
(actor ? cc.addEntitlement(bankId, userId, roleName, createdByProcess: String)).mapTo[Box[Entitlement]]
|
||||
)
|
||||
|
||||
override def deleteDynamicEntityEntitlement(entityName: String, bankId:Option[String]): Box[Boolean] = getValueFromFuture(
|
||||
|
||||
@ -55,9 +55,9 @@ class RemotedataEntitlementsActor extends Actor with ObpActorHelper with MdcLogg
|
||||
logger.debug(s"getEntitlementsByRole($role)")
|
||||
sender ! (mapper.getEntitlementsByRole(role))
|
||||
|
||||
case cc.addEntitlement(bankId: String, userId: String, roleName: String) =>
|
||||
logger.debug(s"addEntitlement($bankId, $userId, $roleName)")
|
||||
sender ! (mapper.addEntitlement(bankId, userId, roleName))
|
||||
case cc.addEntitlement(bankId: String, userId: String, roleName: String, createdByProcess: String) =>
|
||||
logger.debug(s"addEntitlement($bankId, $userId, $roleName, $createdByProcess)")
|
||||
sender ! (mapper.addEntitlement(bankId, userId, roleName, createdByProcess: String))
|
||||
|
||||
case cc.deleteDynamicEntityEntitlement(entityName: String, bankId:Option[String]) =>
|
||||
logger.debug(s"deleteDynamicEntityEntitlement($entityName) bankId($bankId)")
|
||||
|
||||
@ -474,7 +474,7 @@ class ConsumerRegistration extends MdcLoggable {
|
||||
while(matcher.find()) {
|
||||
val userName = matcher.group(1)
|
||||
val password = matcher.group(2)
|
||||
val (code, token) = DirectLogin.createToken(Map(("username", userName), ("password", password), ("consumer_key", consumerKey)))
|
||||
val (code, token, userId) = DirectLogin.createToken(Map(("username", userName), ("password", password), ("consumer_key", consumerKey)))
|
||||
val authHeader = code match {
|
||||
case 200 => (userName, password) -> s"""Authorization: DirectLogin token="$token""""
|
||||
case _ => (userName, password) -> "username or password is invalid, generate token fail"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user