Merge pull request #1566 from constantine2nd/develop

OIDC done; Props alias
This commit is contained in:
Simon Redfern 2020-05-08 18:57:53 +02:00 committed by GitHub
commit 92a29971e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 23 deletions

View File

@ -464,8 +464,24 @@ There are 3 API's endpoint related to webhooks:
2. `PUT ../banks/BANK_ID/account-web-hooks` - Enable/Disable an Account Webhook
3. `GET ../management/banks/BANK_ID/account-web-hooks` - Get Account Webhooks
---
## OAuth 2.0
In order to enable an OAuth2 workflow at an instance of OBP-API backend app you need to setup next props:
## OpenID Connect
In order to enable an OIDC workflow at an instance of OBP-API portal app(login functionality) you need to set-up the following props:
```props
# Google as an identity provider
# openid_connect_1.client_secret=OYdWujJl******_NXzPlDI4T
# openid_connect_1.client_id=883**3244***-s4hi72j0rble0iiivq1gn09k7***tdci.apps.googleusercontent.com
# openid_connect_1.callback_url=http://127.0.0.1:8080/auth/openid-connect/callback
# openid_connect_1.endpoint.authorization=https://accounts.google.com/o/oauth2/v2/auth
# openid_connect_1.endpoint.userinfo=https://openidconnect.googleapis.com/v1/userinfo
# openid_connect_1.endpoint.token=https://oauth2.googleapis.com/token
# openid_connect_1.endpoint.jwks_uri=https://www.googleapis.com/oauth2/v3/certs
# openid_connect_1.access_type_offline=false
```
Please note in the example above you MUST run OBP-API portal at the URL: http://127.0.0.1:8080
## OAuth 2.0 Authentication
In order to enable an OAuth2 workflow at an instance of OBP-API backend app you need to set-up the following props:
```
# -- OAuth 2 ---------------------------------------------------------------------------------
# Enable/Disable OAuth 2 workflow at a server instance

View File

@ -546,6 +546,7 @@ super_admin_user_ids=USER_ID1,USER_ID2,
## registered on OBP localy.
# openid_connect.enabled=true
# First identity provider
# openid_connect_1.button_text = Google
# openid_connect_1.client_secret=OYdWujJlU7fFOW_NXzPlDI4T
# openid_connect_1.client_id=883773244832-s4hi72j0rble0iiivq1gn09k7vvptdci.apps.googleusercontent.com
# openid_connect_1.callback_url=http://127.0.0.1:8080/auth/openid-connect/callback
@ -555,6 +556,7 @@ super_admin_user_ids=USER_ID1,USER_ID2,
# openid_connect_1.endpoint.jwks_uri=https://www.googleapis.com/oauth2/v3/certs
# openid_connect_1.access_type_offline=true
## Second identity provder
# openid_connect_2.button_text = name of 2nd provider
# openid_connect_2.client_secret=OYdWujJlU7fFOW_NXzPlDI4T
# openid_connect_2.client_id=883773244832-s4hi72j0rble0iiivq1gn09k7vvptdci.apps.googleusercontent.com
# openid_connect_2.callback_url=http://127.0.0.1:8080/auth/openid-connect/callback
@ -673,7 +675,7 @@ featured_apis=elasticSearchWarehouseV300
# Enable/Disable execution of migration scripts.
# In case isn't defined default value is "false"
# Note: migration_scripts.execute MUST be true for the other two props values (list_of_migration_scripts_to_execute and migration_scripts) to have any effect.
# migration_scripts.execute=false
# migration_scripts.enabled=false
# Define list of migration scripts to execute.
# List is not ordered.
# list_of_migration_scripts_to_execute=dummyScript

View File

@ -1766,7 +1766,7 @@ Returns a string showed to the developer
)
def requireScopes(role: ApiRole) = {
ApiProperty.requireScopesForAllRoles match {
ApiPropsWithAlias.requireScopesForAllRoles match {
case false =>
getPropsValue("enable_scopes_for_roles").toList.map(_.split(",")).flatten.exists(_ == role.toString())
case true =>

View File

@ -11,11 +11,19 @@ import net.liftweb.common.Full
* 2. We introduce a new name "require_scopes_for_all_roles"
* 3. We have to support all instances with old name in order to allow smooth transition from the old to the new name.
*/
object ApiProperty extends MdcLoggable {
val requireScopesForAllRoles = getValueByNameOrAliasAsBoolean("require_scopes_for_all_roles", "require_scopes", "false")
object ApiPropsWithAlias {
import HelperFunctions._
val requireScopesForAllRoles = getValueByNameOrAliasAsBoolean(
name="require_scopes_for_all_roles",
alias="require_scopes",
defaultValue="false")
val migrationScriptsEnabled = getValueByNameOrAliasAsBoolean(
name="migration_scripts.enabled",
alias="migration_scripts.execute",
defaultValue="false")
}
object HelperFunctions extends MdcLoggable {
/**
* Workflow of get property with boolean value
*
@ -39,13 +47,13 @@ object ApiProperty extends MdcLoggable {
* @param alias The alias of a property
* @return true/false
*/
private def getValueByNameOrAliasAsBoolean(name: String, alias: String, defaultValue: String): Boolean = {
private[util] def getValueByNameOrAliasAsBoolean(name: String, alias: String, defaultValue: String): Boolean = {
getValueByNameOrAlias(name, alias, defaultValue).toBoolean
}
/**
* Workflow of get property with string value
*
1st try 2nd try
1st try 2nd try
get +---------------+ +---------------+
property | | no match | | no match
+----------->+ Name +------------------->+ Alias +----------+
@ -65,17 +73,18 @@ object ApiProperty extends MdcLoggable {
* @param alias The alias of a property
* @return value/default value
*/
private def getValueByNameOrAlias(name: String, alias: String, defaultValue: String): String = {
private[util] def getValueByNameOrAlias(name: String, alias: String, defaultValue: String): String = {
(getPropsValue(name), getPropsValue(alias)) match {
case (Full(actual), Full(deprecated)) => // Both properties are defined. Use actual one and log warning. {true/false}
logger.warn(s"The props file has defined actual property name $name as well as deprecated $alias. The deprecated one is ignored!")
logger.warn(s"The props file has defined actual property $name as well as deprecated $alias. The deprecated one is ignored!")
actual
case (Full(actual), _) => // Only actual name of the property is defined. {true/false}
actual
case (_, Full(deprecated)) => // Only deprecated name of the property is defined. {true/false}
logger.warn(s"The props file uses deprecated property $alias. Please use $name instead of it")
deprecated
case _ => // Not defined. {false}
defaultValue
}
}
}
}

View File

@ -4,7 +4,7 @@ import java.sql.{ResultSet, SQLException}
import java.text.SimpleDateFormat
import java.util.Date
import code.api.util.APIUtil
import code.api.util.{APIUtil, ApiPropsWithAlias}
import code.api.util.APIUtil.{getPropsAsBoolValue, getPropsValue}
import code.consumer.Consumers
import code.customer.CustomerX
@ -18,13 +18,12 @@ import scala.collection.immutable
import scala.collection.mutable.HashMap
object Migration extends MdcLoggable {
private val migrationScriptsEnabled = ApiPropsWithAlias.migrationScriptsEnabled
private val executeAll = getPropsAsBoolValue("migration_scripts.execute_all", false)
private val execute = getPropsAsBoolValue("migration_scripts.execute", false)
private val scriptsToExecute: immutable.Seq[String] = getPropsValue("list_of_migration_scripts_to_execute").toList.map(_.split(",")).flatten
private def executeScript(blockOfCode: => Boolean): Boolean = {
if(execute) blockOfCode else execute
if(migrationScriptsEnabled) blockOfCode else migrationScriptsEnabled
}
private def runOnce(name: String)(blockOfCode: => Boolean): Boolean = {

View File

@ -31,7 +31,7 @@ import java.util.Date
import java.util.regex.Pattern
import code.actorsystem.ObpActorConfig
import code.api.util.{APIUtil, ApiProperty, CustomJsonFormats}
import code.api.util.{APIUtil, ApiPropsWithAlias, CustomJsonFormats}
import code.api.util.APIUtil.{MessageDoc, getPropsValue}
import code.api.v1_2_1.BankRoutingJsonV121
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121}
@ -808,7 +808,7 @@ object JSONFactory220 extends CustomJsonFormats {
val scopes =
ScopesJSON(
ApiProperty.requireScopesForAllRoles,
ApiPropsWithAlias.requireScopesForAllRoles,
getPropsValue("enable_scopes_for_roles").toList.map(_.split(",")).flatten
)

View File

@ -0,0 +1,35 @@
package code.snippet
import code.api.util.APIUtil
import code.util.Helper.MdcLoggable
import net.liftweb.util.{CssSel, PassThru}
import net.liftweb.util.Helpers._
import scala.xml.NodeSeq
class OpenIDConnectSnippet extends MdcLoggable{
@transient protected val log = logger
def getFirstButtonText: CssSel = {
val text = APIUtil.getPropsValue("openid_connect_1.button_text", "OIDC 1")
"#open-id-connect-button-1 *" #> scala.xml.Unparsed(text)
}
def getSecondButtonText: CssSel = {
val text = APIUtil.getPropsValue("openid_connect_2.button_text", "OIDC 2")
"#open-id-connect-button-1 *" #> scala.xml.Unparsed(text)
}
def showFirstButton =
if (APIUtil.getPropsValue("openid_connect_1.client_id").isEmpty)
"*" #> NodeSeq.Empty
else
PassThru
def showSecondButton =
if (APIUtil.getPropsValue("openid_connect_2.client_id").isEmpty)
"*" #> NodeSeq.Empty
else
PassThru
}

View File

@ -35,19 +35,19 @@
<a href="/user_mgt/lost_password" id="authorise-recover-password" tabindex="5">Recover password</a>
</div>
</div>
<div class="row">
<div class="row" data-lift="OpenIDConnectSnippet.showFirstButton">
<div class="col-xs-6"></div>
<div class="col-xs-6" data-lift="OpenidConnectInvoke.linkButtonFirstProvider">
<div class="authorise-button-oidc">
Log in with: <a class="btn btn-default">OIDC 1</a>
Log in with: <a id="open-id-connect-button-1" data-lift="OpenIDConnectSnippet.getFirstButtonText" class="btn btn-default">OIDC 1</a>
</div>
</div>
</div>
<div class="row">
<div class="row" data-lift="OpenIDConnectSnippet.showSecondButton">
<div class="col-xs-6"></div>
<div class="col-xs-6" data-lift="OpenidConnectInvoke.linkButtonSecondProvider">
<div class="authorise-button-oidc">
Log in with: <a class="btn btn-default">OIDC 2</a>
Log in with: <a id="open-id-connect-button-2" data-lift="OpenIDConnectSnippet.getSecondButtonText" class="btn btn-default">OIDC 2</a>
</div>
</div>
</div>