mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 17:37:00 +00:00
feature/Introduce props oauth2.keycloak.source-of-truth
This commit is contained in:
parent
9532f5eb21
commit
513fd7e4e8
@ -767,6 +767,8 @@ display_internal_errors=false
|
||||
# Keycloak Identity Provider Host
|
||||
# oauth2.keycloak.host=http://localhost:7070
|
||||
# oauth2.keycloak.well-known=http://localhost:7070/realms/master/.well-known/openid-configuration
|
||||
# Used to sync IAM of OBP-API and IAM of Keycloak
|
||||
# oauth2.keycloak.source-of-truth = false
|
||||
# ------------------------------------------------------------------------------ OAuth 2 ------
|
||||
|
||||
## This property is used for documenting at Resource Doc. It may include the port also (but not /obp)
|
||||
|
||||
@ -26,28 +26,29 @@ TESOBE (http://www.tesobe.com/)
|
||||
*/
|
||||
package code.api
|
||||
|
||||
import java.net.URI
|
||||
import java.util
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.{APIUtil, CallContext, CertificateUtil, JwtUtil}
|
||||
import code.api.util._
|
||||
import code.consumer.Consumers
|
||||
import code.consumer.Consumers.consumers
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.model.{AppType, Consumer}
|
||||
import code.util.HydraUtil._
|
||||
import code.scope.Scope
|
||||
import code.users.Users
|
||||
import code.util.Helper.MdcLoggable
|
||||
import code.util.HydraUtil
|
||||
import code.util.HydraUtil._
|
||||
import com.nimbusds.jwt.JWTClaimsSet
|
||||
import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.model.User
|
||||
import net.liftweb.common.Box.tryo
|
||||
import net.liftweb.common._
|
||||
import net.liftweb.http.rest.RestHelper
|
||||
import net.liftweb.util.Helpers
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import sh.ory.hydra.model.OAuth2TokenIntrospection
|
||||
|
||||
import java.net.URI
|
||||
import scala.concurrent.Future
|
||||
import scala.jdk.CollectionConverters.mapAsJavaMapConverter
|
||||
|
||||
@ -226,7 +227,7 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
}
|
||||
}
|
||||
|
||||
private def getClaim(name: String, idToken: String): Option[String] = {
|
||||
def getClaim(name: String, idToken: String): Option[String] = {
|
||||
val claim = JwtUtil.getClaim(name = name, jwtToken = idToken)
|
||||
claim match {
|
||||
case null => None
|
||||
@ -373,6 +374,7 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
redirectURL = None,
|
||||
createdByUserId = userId.toOption
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
def applyIdTokenRules(token: String, cc: CallContext): (Box[User], Some[CallContext]) = {
|
||||
@ -471,10 +473,44 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
def applyRules(token: String, cc: CallContext): (Box[User], Some[CallContext]) = {
|
||||
JwtUtil.getClaim("typ", token) match {
|
||||
case "ID" => super.applyIdTokenRules(token, cc)
|
||||
case "Bearer" => super.applyAccessTokenRules(token, cc)
|
||||
case "Bearer" =>
|
||||
val result = super.applyAccessTokenRules(token, cc)
|
||||
addScopesToConsumer(token)
|
||||
result
|
||||
case "" => super.applyAccessTokenRules(token, cc)
|
||||
}
|
||||
}
|
||||
|
||||
private def addScopesToConsumer(token: String): Unit = {
|
||||
val sourceOfTruth = APIUtil.getPropsAsBoolValue(nameOfProperty = "oauth2.keycloak.source-of-truth", defaultValue = false)
|
||||
val consumerId = getClaim(name = "azp", idToken = token).getOrElse("")
|
||||
if(sourceOfTruth) {
|
||||
logger.debug("Extracting roles from Access Token")
|
||||
import net.liftweb.json._
|
||||
val jsonString = JwtUtil.getSignedPayloadAsJson(token)
|
||||
val json = parse(jsonString.getOrElse(""))
|
||||
val openBankRoles: List[String] = {
|
||||
(json \ "resource_access" \ consumerId \ "roles").extract[List[String]]
|
||||
.filter(role => tryo(ApiRole.valueOf(role)).isDefined) // Keep only the roles OBP-API can recognise
|
||||
}
|
||||
val scopes = Scope.scope.vend.getScopesByConsumerId(consumerId).getOrElse(Nil)
|
||||
val databaseState = scopes.map(_.roleName)
|
||||
// Already exist at DB
|
||||
val existingRoles = openBankRoles.intersect(databaseState)
|
||||
// Roles to add into DB
|
||||
val rolesToAdd = openBankRoles.toSet diff databaseState.toSet
|
||||
rolesToAdd.foreach(roleName => Scope.scope.vend.addScope("", consumerId, roleName))
|
||||
// Roles to delete from DB
|
||||
val rolesToDelete = databaseState.toSet diff openBankRoles.toSet
|
||||
rolesToDelete.foreach( roleName =>
|
||||
Scope.scope.vend.deleteScope(scopes.find(s => s.roleName == roleName || s.consumerId == consumerId))
|
||||
)
|
||||
logger.debug(s"Consumer ID: $consumerId # Existing roles: ${existingRoles.mkString} # Added roles: ${rolesToAdd.mkString} # Deleted roles: ${rolesToDelete.mkString}")
|
||||
} else {
|
||||
logger.debug(s"Adding scopes omitted due to oauth2.keycloak.source-of-truth = $sourceOfTruth # Consumer ID: $consumerId")
|
||||
}
|
||||
}
|
||||
|
||||
def applyRulesFuture(value: String, cc: CallContext): Future[(Box[User], Some[CallContext])] = Future {
|
||||
applyRules(value, cc)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user