From 2ca237cfdcff812a116e96b55a021f4ecc4c0692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 22 Oct 2019 13:05:45 +0200 Subject: [PATCH 1/7] Tweaked names regarding account tags --- completed_developments.md | 2 +- .../SwaggerDefinitionsJSON.scala | 19 ++++++-- .../scala/code/api/v4_0_0/APIMethods400.scala | 14 +++--- .../code/api/v4_0_0/JSONFactory4.0.0.scala | 43 +++++++++++++++---- .../code/api/v4_0_0/AccountTagTest.scala | 7 ++- .../commons/model/ViewModel.scala | 4 +- 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/completed_developments.md b/completed_developments.md index 4caf3758b..2c8aae3e1 100644 --- a/completed_developments.md +++ b/completed_developments.md @@ -177,7 +177,7 @@ The two user models are now called AuthUser and ResourceUser * Answer Transaction Request Challenge (updated) * Get Transaction Requests (updated) * Get Roles (new) -* Get Entitlements By Bank And User (naaew) +* Get Entitlements By Bank And User (new) * Get Consumer (App) (new) * Get Consumers (App) (new) * Enable Disable Consumers (Apps) (new) diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index cc9958e8a..b4a94f325 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -15,7 +15,7 @@ import code.api.v3_0_0.JSONFactory300.createBranchJsonV300 import code.api.v3_0_0.custom.JSONFactoryCustom300 import code.api.v3_0_0.{LobbyJsonV330, _} import code.api.v3_1_0.{AccountBalanceV310, AccountsBalancesV310Json, BadLoginStatusJson, ContactDetailsJson, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _} -import code.api.v4_0_0.{APIInfoJson400, EnergySource400, HostedAt400, HostedBy400, ModeratedCoreAccountJsonV400} +import code.api.v4_0_0.{APIInfoJson400, AccountTagJSON, AccountTagsJSON, EnergySource400, HostedAt400, HostedBy400, ModeratedCoreAccountJsonV400, PostAccountTagJSON} import code.branches.Branches.{Branch, DriveUpString, LobbyString} import code.consent.ConsentStatus import code.sandbox.SandboxData @@ -505,6 +505,9 @@ object SwaggerDefinitionsJSON { val postTransactionTagJSON = PostTransactionTagJSON( value = "String" ) + val postAccountTagJSON = PostAccountTagJSON( + value = "String" + ) val aliasJSON = AliasJSON( alias = "String" ) @@ -895,6 +898,16 @@ object SwaggerDefinitionsJSON { tags = List(transactionTagJSON) ) + val accountTagJSON = AccountTagJSON( + id = "5995d6a2-01b3-423c-a173-5481df49bdaf", + value = "OBP", + date = DateWithDayExampleObject, + user = userJSONV121 + ) + val accountTagsJSON = AccountTagsJSON( + tags = List(accountTagJSON) + ) + val transactionMetadataJSON = TransactionMetadataJSON( narrative = "NONE", comments = List(transactionCommentJSON), @@ -3367,7 +3380,7 @@ object SwaggerDefinitionsJSON { views_basic = List(viewBasicV300), account_attributes = List(accountAttributeResponseJson) ) - val newModeratedCoreAccountJsonV400 = ModeratedCoreAccountJsonV400( + val moderatedCoreAccountJsonV400 = ModeratedCoreAccountJsonV400( id = accountIdExample.value, bank_id= bankIdExample.value, label= labelExample.value, @@ -3378,7 +3391,7 @@ object SwaggerDefinitionsJSON { account_routings = List(accountRoutingJsonV121), views_basic = List(viewBasicV300), account_attributes = List(accountAttributeResponseJson), - tags = List(transactionTagJSON) + tags = List(accountTagJSON) ) val postHistoricalTransactionJson = PostHistoricalTransactionJson( diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 21899749d..c6af13831 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -1104,8 +1104,8 @@ trait APIMethods400 { |${authenticationRequiredMessage(true)} | |Authentication is required as the tag is linked with the user.""", - postTransactionTagJSON, - transactionTagJSON, + postAccountTagJSON, + accountTagJSON, List( UserNotLoggedIn, BankAccountNotFound, @@ -1136,7 +1136,7 @@ trait APIMethods400 { i => (connectorEmptyResponse(i, callContext), callContext) } } yield { - (JSONFactory.createTransactionTagJSON(postedTag), HttpCode.`201`(callContext)) + (JSONFactory400.createAccountTagJSON(postedTag), HttpCode.`201`(callContext)) } } } @@ -1196,7 +1196,7 @@ trait APIMethods400 { | |Authentication is required as the tag is linked with the user.""", emptyObjectJson, - transactionTagJSON, + accountTagsJSON, List( BankAccountNotFound, NoViewPermission, @@ -1221,7 +1221,7 @@ trait APIMethods400 { } tags <- Future(Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId)) } yield { - val json = JSONFactory.createTransactionTagsJSON(tags) + val json = JSONFactory400.createAccountTagsJSON(tags) (json, HttpCode.`200`(callContext)) } } @@ -1246,6 +1246,8 @@ trait APIMethods400 { |* Balance - Currency and Value |* Account Routings - A list that might include IBAN or national account identifiers |* Account Rules - A list that might include Overdraft and other bank specific rules + |* Account Attributes - A list that might include custom defined account attribute + |* Tags - A list of Tags assigned to this account | |This call returns the owner view and requires access to that view. | @@ -1254,7 +1256,7 @@ trait APIMethods400 { | |""".stripMargin, emptyObjectJson, - newModeratedCoreAccountJsonV400, + moderatedCoreAccountJsonV400, List(BankAccountNotFound,UnknownError), Catalogs(Core, PSD2, notOBWG), apiTagAccount :: apiTagPSD2AIS :: apiTagNewStyle :: Nil) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala index d28f3f2b0..b23cd8f41 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala @@ -30,18 +30,17 @@ import java.util.Date import code.api.util.APIUtil import code.api.util.APIUtil.{stringOptionOrNull, stringOrNull} -import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON, createTransactionTagJSON} -import code.api.v1_2_1.{BankRoutingJsonV121, TransactionTagJSON, UserJSONV121, ViewJSONV121} +import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON} +import code.api.v1_2_1.{BankRoutingJsonV121, JSONFactory, UserJSONV121, ViewJSONV121} import code.api.v1_4_0.JSONFactory1_4_0.TransactionRequestAccountJsonV140 import code.api.v2_0_0.TransactionRequestChargeJsonV200 import code.api.v3_0_0.JSONFactory300.createAccountRoutingsJSON -import code.api.v3_0_0.{NewModeratedCoreAccountJsonV300, ViewBasicV300} +import code.api.v3_0_0.ViewBasicV300 import code.api.v3_1_0.AccountAttributeResponseJson import code.api.v3_1_0.JSONFactory310.createAccountAttributeJson import code.model.ModeratedBankAccount import code.transactionrequests.TransactionRequests.TransactionChallengeTypes -import code.transactionrequests.TransactionRequests.TransactionRequestTypes.ACCOUNT_OTP -import com.openbankproject.commons.model.{AccountAttribute, AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, TransactionRequest, TransactionRequestBodyAllTypes, TransactionTag, View} +import com.openbankproject.commons.model._ import scala.collection.immutable.List @@ -114,7 +113,7 @@ case class ModeratedCoreAccountJsonV400( account_routings: List[AccountRoutingJsonV121], views_basic: List[ViewBasicV300], account_attributes: List[AccountAttributeResponseJson], - tags: List[TransactionTagJSON] + tags: List[AccountTagJSON] ) case class ModeratedAccountJSON400( @@ -128,9 +127,22 @@ case class ModeratedAccountJSON400( bank_id : String, account_routing :AccountRoutingJsonV121, account_attributes: List[AccountAttributeResponseJson], - tags: List[TransactionTagJSON] + tags: List[AccountTagJSON] ) +case class AccountTagJSON( + id : String, + value : String, + date : Date, + user : UserJSONV121 + ) + +case class AccountTagsJSON( + tags: List[AccountTagJSON] + ) +case class PostAccountTagJSON( + value : String + ) object JSONFactory400 { def createBankJSON400(bank: Bank): BankJson400 = { val obp = BankRoutingJsonV121("OBP", bank.bankId.value) @@ -227,7 +239,7 @@ object JSONFactory400 { createAccountRoutingsJSON(account.accountRoutings), views_basic = availableViews.map(view => code.api.v3_0_0.ViewBasicV300(id = view.viewId.value, short_name = view.name, description = view.description, is_public = view.isPublic)), accountAttributes.map(createAccountAttributeJson), - tags.map(createTransactionTagJSON) + tags.map(createAccountTagJSON) ) } @@ -248,7 +260,20 @@ object JSONFactory400 { stringOrNull(account.bankId.value), AccountRoutingJsonV121(stringOptionOrNull(account.accountRoutingScheme),stringOptionOrNull(account.accountRoutingAddress)), accountAttributes.map(createAccountAttributeJson), - tags.map(createTransactionTagJSON) + tags.map(createAccountTagJSON) + ) + } + + + def createAccountTagsJSON(tags : List[TransactionTag]) : AccountTagsJSON = { + new AccountTagsJSON(tags.map(createAccountTagJSON)) + } + def createAccountTagJSON(tag : TransactionTag) : AccountTagJSON = { + new AccountTagJSON( + id = tag.id_, + value = tag.value, + date = tag.datePosted, + user = JSONFactory.createUserJSON(tag.postedBy) ) } diff --git a/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala index c5a862613..88c21b5cb 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/AccountTagTest.scala @@ -5,7 +5,6 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON import code.api.util.APIUtil.OAuth._ import code.api.util.ApiVersion import code.api.util.ErrorMessages.UserNotLoggedIn -import code.api.v1_2_1.{TransactionTagJSON, TransactionTagsJSON} import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0 import com.github.dwickern.macros.NameOf.nameOf import net.liftweb.json.Serialization.write @@ -24,7 +23,7 @@ class AccountTagTest extends V400ServerSetup { object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.deleteTagForViewOnAccount)) object ApiEndpoint3 extends Tag(nameOf(Implementations4_0_0.getTagsForViewOnAccount)) - lazy val accountTag = SwaggerDefinitionsJSON.transactionTagJSON + lazy val accountTag = SwaggerDefinitionsJSON.accountTagJSON lazy val bankId = randomBankId lazy val bankAccount = randomPrivateAccount(bankId) lazy val view = randomOwnerViewPermalink(bankId, bankAccount) @@ -71,12 +70,12 @@ class AccountTagTest extends V400ServerSetup { Then("We should get a 201 and check the response body") response.code should equal(201) - response.body.extract[TransactionTagJSON] + response.body.extract[AccountTagJSON] val requestGet = (v4_0_0_Request / "banks" / bankId / "accounts" / bankAccount.id / view / "metadata" / "tags").GET <@ (user1) val responseGet = makeGetRequest(requestGet) responseGet.code should equal(200) - val tags = responseGet.body.extract[TransactionTagsJSON].tags + val tags = responseGet.body.extract[AccountTagsJSON].tags tags.exists(_.value == accountTag.value) equals true val tagId = tags.map(_.id).headOption.getOrElse("") diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala index ff7e50a8c..5d68507aa 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala @@ -164,8 +164,8 @@ case class UpdateViewJSON( * @define canEditOwnerComment If true, the view can edit the Transaction Owner Comment * @define canAddComment If true, the view can add a Transaction Comment * @define canDeleteComment If true, the view can delete a Transaction Comment - * @define canAddTag If true, the view can add a Transaction Tag - * @define canDeleteTag If true, the view can delete a Transaction Tag + * @define canAddTag If true, the view can add a Transaction/Account Tag + * @define canDeleteTag If true, the view can delete a Transaction/Account Tag * @define canAddImage If true, the view can add a Transaction Image * @define canDeleteImage If true, the view can delete a Transaction Image * @define canAddWhereTag If true, the view can add a Transaction Where Tag From cc86b339fcb749193ba49ee5318d7aea482a8642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 22 Oct 2019 15:20:39 +0200 Subject: [PATCH 2/7] Improved endpoint createConsent v3.1.0 --- .../SwaggerDefinitionsJSON.scala | 14 ++++--- .../scala/code/api/util/ConsentUtil.scala | 39 ++++++++++++------- .../scala/code/api/v3_1_0/APIMethods310.scala | 2 +- .../code/api/v3_1_0/JSONFactory3.1.0.scala | 27 +++++++------ 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index b4a94f325..9b32453ed 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -3261,15 +3261,17 @@ object SwaggerDefinitionsJSON { ) val postConsentEmailJsonV310 = PostConsentEmailJsonV310( - `for` = "ALL_MY_ACCOUNTS", - view = "owner", - email = "marko@tesobe.com" + everything = false, + views = List(ViewJsonV400(bankIdExample.value, accountIdExample.value, viewIdExample.value)), + entitlements = List(EntitlementJsonV400(bankIdExample.value, "CanQueryOtherUser")), + email = emailExample.value ) val postConsentPhoneJsonV310 = PostConsentPhoneJsonV310( - `for` = "ALL_MY_ACCOUNTS", - view = "owner", - phone_number = "493081453994" + everything = false, + views = List(ViewJsonV400(bankIdExample.value, accountIdExample.value, viewIdExample.value)), + entitlements = List(EntitlementJsonV400(bankIdExample.value, "CanQueryOtherUser")), + phone_number = mobileNumberExample.value ) val consentsJsonV310 = ConsentsJsonV310(List(consentJsonV310)) diff --git a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala index d894ae59f..d4767ac9e 100644 --- a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala +++ b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala @@ -1,5 +1,6 @@ package code.api.util +import code.api.v3_1_0.{EntitlementJsonV400, PostConsentBodyCommonJson, ViewJsonV400} import code.consent.{ConsentStatus, Consents, MappedConsent} import code.consumer.Consumers import code.entitlement.Entitlement @@ -13,6 +14,7 @@ import net.liftweb.json.JsonParser.ParseException import net.liftweb.json.{Extraction, MappingException, compactRender} import net.liftweb.mapper.By +import scala.collection.immutable.List import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -310,21 +312,30 @@ object Consent { } - def createConsentJWT(user: User, viewId: String, secret: String, consentId: String): String = { + def createConsentJWT(user: User, + consent: PostConsentBodyCommonJson, + secret: String, + consentId: String): String = { val consumerKey = Consumer.findAll(By(Consumer.createdByUserId, user.userId)).map(_.key.get).headOption.getOrElse("") val currentTimeInSeconds = System.currentTimeMillis / 1000 - val views: Box[List[ConsentView]] = { - Views.views.vend.getPermissionForUser(user) map { - _.views map { - view => - ConsentView( - bank_id = view.bankId.value, - account_id = view.accountId.value, - view_id = viewId - ) - } + val views: Seq[ConsentView] = + for { + view <- Views.views.vend.getPermissionForUser(user).map(_.views).getOrElse(Nil) + if consent.everything || consent.views.exists(_ == ViewJsonV400(view.bankId.value,view.accountId.value, view.viewId.value)) + } yield { + ConsentView( + bank_id = view.bankId.value, + account_id = view.accountId.value, + view_id = view.viewId.value + ) + } + val entitlements: Seq[Role] = + for { + entitlement <- Entitlement.entitlement.vend.getEntitlementsByUserId(user.userId).getOrElse(Nil) + if consent.everything || consent.entitlements.exists(_ == EntitlementJsonV400(entitlement.bankId,entitlement.roleName)) + } yield { + Role(entitlement.roleName, entitlement.bankId) } - }.map(_.distinct) val json = ConsentJWT( createdByUserId=user.userId, sub=APIUtil.generateUUID(), @@ -336,8 +347,8 @@ object Consent { exp=currentTimeInSeconds + 3600, name=None, email=None, - entitlements=Nil, - views=views.getOrElse(Nil) + entitlements=entitlements.toList, + views=views.toList ) implicit val formats = CustomJsonFormats.formats diff --git a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala index 58986a864..f119b0060 100644 --- a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala +++ b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala @@ -3390,7 +3390,7 @@ trait APIMethods310 { createdConsent <- Future(Consents.consentProvider.vend.createConsent(user)) map { i => connectorEmptyResponse(i, callContext) } - consentJWT = Consent.createConsentJWT(user, consentJson.view, createdConsent.secret, createdConsent.consentId) + consentJWT = Consent.createConsentJWT(user, consentJson, createdConsent.secret, createdConsent.consentId) _ <- Future(Consents.consentProvider.vend.setJsonWebToken(createdConsent.consentId, consentJWT)) map { i => connectorEmptyResponse(i, callContext) } diff --git a/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala b/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala index a3343cf43..6cda4afb0 100644 --- a/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala +++ b/obp-api/src/main/scala/code/api/v3_1_0/JSONFactory3.1.0.scala @@ -490,27 +490,32 @@ case class MeetingJsonV310( case class MeetingsJsonV310( meetings: List[MeetingJsonV310] ) - +case class EntitlementJsonV400(bank_id: String, role_name: String) +case class ViewJsonV400(bank_id: String, account_id: String, view_id: String) trait PostConsentCommonBody{ - val `for`: String - val view: String + val everything: Boolean + val views: List[ViewJsonV400] + val entitlements: List[EntitlementJsonV400] } case class PostConsentBodyCommonJson( - `for`: String, - view: String + everything: Boolean, + views: List[ViewJsonV400], + entitlements: List[EntitlementJsonV400] ) extends PostConsentCommonBody case class PostConsentEmailJsonV310( - `for`: String, - view: String, - email: String + everything: Boolean, + views: List[ViewJsonV400], + entitlements: List[EntitlementJsonV400], + email: String ) extends PostConsentCommonBody case class PostConsentPhoneJsonV310( - `for`: String, - view: String, - phone_number: String + everything: Boolean, + views: List[ViewJsonV400], + entitlements: List[EntitlementJsonV400], + phone_number: String ) extends PostConsentCommonBody case class ConsentJsonV310(consent_id: String, jwt: String, status: String) From 06b570c1a45178d802657b4d355a709593ec6a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Wed, 23 Oct 2019 14:06:47 +0200 Subject: [PATCH 3/7] Added function convertGitHubDocMarkdownToHtml --- obp-api/src/main/scala/code/api/util/Pegdown.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/api/util/Pegdown.scala b/obp-api/src/main/scala/code/api/util/Pegdown.scala index 8af137d82..c551b7427 100644 --- a/obp-api/src/main/scala/code/api/util/Pegdown.scala +++ b/obp-api/src/main/scala/code/api/util/Pegdown.scala @@ -32,8 +32,10 @@ object PegdownOptions { // convertPegdownToHtmlTweaked not support insert image, so here manual convert to html img tag private def convertImgTag(markdown: String) = markdown.stripMargin.replaceAll("""!\[(.*)\]\((.*) =(.*?)x(.*?)\)""", """$1""") - def convertMarkdownToHtml(description: String): String = { + def convertGitHubDocMarkdownToHtml(description: String): String = { val options = new MutableDataSet() + import com.vladsch.flexmark.parser.ParserEmulationProfile + options.setFrom(ParserEmulationProfile.GITHUB_DOC) val parser = Parser.builder(options).build val renderer = HtmlRenderer.builder(options).build val document = parser.parse(description.stripMargin) From c6e5185352035bd49aca1ca7e1065488f14b75f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Wed, 23 Oct 2019 16:18:44 +0200 Subject: [PATCH 4/7] Added function WebUI.makeHtml --- obp-api/src/main/scala/code/snippet/WebUI.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/obp-api/src/main/scala/code/snippet/WebUI.scala b/obp-api/src/main/scala/code/snippet/WebUI.scala index 27388fd57..9e8c44d1f 100644 --- a/obp-api/src/main/scala/code/snippet/WebUI.scala +++ b/obp-api/src/main/scala/code/snippet/WebUI.scala @@ -43,6 +43,20 @@ class WebUI extends MdcLoggable{ @transient protected val log = logger //Logger(this.getClass) + /** + * This function transform GitHub markdown to html. + * In case text contains html tag we avoid conversion. + * @param text markdown/html + * @return html code + */ + def makeHtml(text: String) = { + val hasHtmlTag = """<[^>]*>""".r.findFirstIn(text).isDefined + hasHtmlTag match { + case false => PegdownOptions.convertGitHubDocMarkdownToHtml(text) + case true => text + } + } + // Cookie Consent button. // Note we don't currently (7th Jan 2017) need to display the cookie consent message due to our limited use of cookies // If a deployment does make more use of cookies we would need to add a No button and we might want to make use of the From 0a7308a41d4b9528498abf42fe614a02e44ea486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Fri, 25 Oct 2019 15:02:15 +0200 Subject: [PATCH 5/7] Create consumer implicitly during OAuth2 workflow --- .../main/scala/code/api/GatewayLogin.scala | 1 + obp-api/src/main/scala/code/api/OAuth2.scala | 29 +++++++++++++++++-- .../code/consumer/ConsumerProvider.scala | 4 +-- obp-api/src/main/scala/code/model/OAuth.scala | 15 ++++++++-- .../code/remotedata/RemotedataConsumers.scala | 4 +-- .../remotedata/RemotedataConsumersActor.scala | 4 +-- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/obp-api/src/main/scala/code/api/GatewayLogin.scala b/obp-api/src/main/scala/code/api/GatewayLogin.scala index faf30ee8f..703feca28 100755 --- a/obp-api/src/main/scala/code/api/GatewayLogin.scala +++ b/obp-api/src/main/scala/code/api/GatewayLogin.scala @@ -353,6 +353,7 @@ object GatewayLogin extends RestHelper with MdcLoggable { consumerId=Some(consumerId), Some(Helpers.randomString(40).toLowerCase), Some(Helpers.randomString(40).toLowerCase), + None, Some(true), name = Some(consumerName), appType = None, diff --git a/obp-api/src/main/scala/code/api/OAuth2.scala b/obp-api/src/main/scala/code/api/OAuth2.scala index 35412e04e..4590bbf77 100644 --- a/obp-api/src/main/scala/code/api/OAuth2.scala +++ b/obp-api/src/main/scala/code/api/OAuth2.scala @@ -29,6 +29,8 @@ package code.api import java.net.URI import code.api.util.{APIUtil, CallContext, ErrorMessages, JwtUtil} +import code.consumer.Consumers +import code.model.Consumer import code.users.Users import code.util.Helper.MdcLoggable import com.nimbusds.jwt.JWTClaimsSet @@ -36,6 +38,7 @@ import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet import com.openbankproject.commons.model.User import net.liftweb.common._ import net.liftweb.http.rest.RestHelper +import net.liftweb.util.Helpers import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -233,11 +236,32 @@ object OAuth2Login extends RestHelper with MdcLoggable { } } + def getOrCreateConsumerFuture(idToken: String, userId: Box[String]): Box[Consumer] = { + val azp = getClaim(name = "azp", idToken = idToken) + val iss = getClaim(name = "iss", idToken = idToken) + val email = getClaim(name = "email", idToken = idToken) + val name = getClaim(name = "name", idToken = idToken) + Consumers.consumers.vend.getOrCreateConsumer( + consumerId = None, + key = Some(Helpers.randomString(40).toLowerCase), + secret = Some(Helpers.randomString(40).toLowerCase), + azp = azp, + Some(true), + name = name, + appType = None, + description = iss.map(v => "Via " + v), + developerEmail = email, + redirectURL = None, + createdByUserId = userId.toOption + ) + } + def applyRules(value: String, cc: CallContext): (Box[User], Some[CallContext]) = { validateIdToken(value) match { case Full(_) => val user = Google.getOrCreateResourceUser(value) - (user, Some(cc)) + val consumer = Google.getOrCreateConsumerFuture(value, user.map(_.userId)) + (user, Some(cc.copy(consumer = consumer))) case ParamFailure(a, b, c, apiFailure : APIFailure) => (ParamFailure(a, b, c, apiFailure : APIFailure), Some(cc)) case Failure(msg, t, c) => @@ -251,8 +275,9 @@ object OAuth2Login extends RestHelper with MdcLoggable { case Full(_) => for { user <- Google.getOrCreateResourceUserFuture(value) + consumer <- Future{Google.getOrCreateConsumerFuture(value, user.map(_.userId))} } yield { - (user, Some(cc)) + (user, Some(cc.copy(consumer = consumer))) } case ParamFailure(a, b, c, apiFailure : APIFailure) => Future((ParamFailure(a, b, c, apiFailure : APIFailure), Some(cc))) diff --git a/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala b/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala index b3b3e6586..62cb44f74 100644 --- a/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala +++ b/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala @@ -33,7 +33,7 @@ trait ConsumersProvider { def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]] - def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] def populateMissingUUIDs(): Boolean } @@ -50,7 +50,7 @@ class RemotedataConsumersCaseClasses { case class createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) case class updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]) - case class getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) case class populateMissingUUIDs() } diff --git a/obp-api/src/main/scala/code/model/OAuth.scala b/obp-api/src/main/scala/code/model/OAuth.scala index a3f318c71..e6aec6b12 100644 --- a/obp-api/src/main/scala/code/model/OAuth.scala +++ b/obp-api/src/main/scala/code/model/OAuth.scala @@ -280,6 +280,7 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { override def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], + azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], @@ -288,7 +289,10 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = { - Consumer.find(By(Consumer.consumerId, consumerId.getOrElse(Helpers.randomString(40)))) match { + val consumer = Consumer.find(By(Consumer.consumerId, consumerId.getOrElse("None"))) or { + Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.createdByUserId, createdByUserId.getOrElse("None"))) + } + consumer match { case Full(c) => Full(c) case Failure(msg, t, c) => Failure(msg, t, c) case ParamFailure(x,y,z,q) => ParamFailure(x,y,z,q) @@ -303,6 +307,10 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { case Some(v) => c.secret(v) case None => } + azp match { + case Some(v) => c.azp(v) + case None => + } isActive match { case Some(v) => c.isActive(v) case None => @@ -407,6 +415,9 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{ object key extends MappedString(this, 250) object secret extends MappedString(this, 250) + object azp extends MappedString(this, 250) { + override def defaultValue = null + } object isActive extends MappedBoolean(this){ override def defaultValue = APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) } @@ -465,7 +476,7 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{ */ object Consumer extends Consumer with MdcLoggable with LongKeyedMetaMapper[Consumer] with CRUDify[Long, Consumer]{ - override def dbIndexes = UniqueIndex(key) :: super.dbIndexes + override def dbIndexes = UniqueIndex(key) :: UniqueIndex(azp, createdByUserId) :: super.dbIndexes //list all path : /admin/consumer/list override def calcPrefix = List("admin",_dbTableNameLC) diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala b/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala index a65ca8a9f..a23627e87 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala @@ -54,8 +54,8 @@ object RemotedataConsumers extends ObpActorInit with ConsumersProvider { def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]] = (actor ? cc.updateConsumerCallLimits(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth)).mapTo[Box[Consumer]] - def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture( - (actor ? cc.getOrCreateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]] + def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture( + (actor ? cc.getOrCreateConsumer(consumerId, key, secret, azp, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]] ) def populateMissingUUIDs(): Boolean = getValueFromFuture( (actor ? cc.populateMissingUUIDs()).mapTo[Boolean] diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala b/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala index eed78a4ba..418483bbb 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala @@ -53,9 +53,9 @@ class RemotedataConsumersActor extends Actor with ObpActorHelper with MdcLoggabl logger.debug("updateConsumerCallLimits(" + id + ", " + perSecond.getOrElse("None")+ ", " + perMinute.getOrElse("None") + ", " + perHour.getOrElse("None") + ", " + perDay.getOrElse("None") + ", " + perWeek.getOrElse("None") + ", " + perMonth.getOrElse("None") + ")") sender ! (mapper.updateConsumerCallLimitsRemote(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth)) - case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) => + case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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") + ")") - sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)) + sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, azp, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)) case cc.populateMissingUUIDs() => logger.debug("populateMissingUUIDs()") From 67f125bd38efeb2ff023c26580d53c310a647735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Fri, 25 Oct 2019 16:34:26 +0200 Subject: [PATCH 6/7] Create consumer implicitly during OAuth2 workflow - added comments --- obp-api/src/main/scala/code/api/OAuth2.scala | 18 +++++++++++++++++- obp-api/src/main/scala/code/model/OAuth.scala | 9 ++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/obp-api/src/main/scala/code/api/OAuth2.scala b/obp-api/src/main/scala/code/api/OAuth2.scala index 4590bbf77..052bce4c4 100644 --- a/obp-api/src/main/scala/code/api/OAuth2.scala +++ b/obp-api/src/main/scala/code/api/OAuth2.scala @@ -235,7 +235,23 @@ object OAuth2Login extends RestHelper with MdcLoggable { ) } } - + /** + * This function creates a consumer based on "azp", "iss", "name" and "email" fields + * Please note that a user must be created before consumer. + * Unique criteria to decide do we create or get a consumer is pair o values: < createdByUserId : azp > i.e. + * We cannot find consumer by createdByUserId and azp => Create + * We can find consumer by createdByUserId and azp => Get + * @param idToken Google's response example: + * { + * "access_token": "ya29.GluUBg5DflrJciFikW5hqeKEp9r1whWnU5x2JXCm9rKkRMs2WseXX8O5UugFMDsIKuKCZlE7tTm1fMII_YYpvcMX6quyR5DXNHH8Lbx5TrZN__fA92kszHJEVqPc", + * "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA4ZDMyNDVjNjJmODZiNjM2MmFmY2JiZmZlMWQwNjk4MjZkZDFkYzEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI0MDc0MDg3MTgxOTIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTM5NjY4NTQyNDU3ODA4OTI5NTkiLCJlbWFpbCI6Im1hcmtvLm1pbGljLnNyYmlqYUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6Im5HS1JUb0tOblZBMjhINk1od1hCeHciLCJuYW1lIjoiTWFya28gTWlsacSHIiwicGljdHVyZSI6Imh0dHBzOi8vbGg1Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tWGQ0NGhuSjZURG8vQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQUt4cndjYWR3emhtNE40dFdrNUU4QXZ4aS1aSzZrczRxZy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiTWFya28iLCJmYW1pbHlfbmFtZSI6Ik1pbGnEhyIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTQ3NzA1NjkxLCJleHAiOjE1NDc3MDkyOTF9.iUxhF_SU2vi76zPuRqAKJvFOzpb_EeP3lc5u9FO9o5xoXzVq3QooXexTfK2f1YAcWEy9LSftA34PB0QTuCZpkQChZVM359n3a3hplf6oWWkBXZN2_IG10NwEH4g0VVBCsjWBDMp6lvepN_Zn15x8opUB7272m4-smAou_WmUPTeivXRF8yPcp4J55DigcY31YP59dMQr2X-6Rr1vCRnJ6niqqJ1UDldfsgt4L7dXmUCnkDdXHwEQAZwbKbR4dUoEha3QeylCiBErmLdpIyqfKECphC6piGXZB-rRRqLz41WNfuF-3fswQvGmIkzTJDR7lQaletMp7ivsfVw8N5jFxg", + * "expires_in": 3600, + * "token_type": "Bearer", + * "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email", + * "refresh_token": "1/HkTtUahtUTdG7D6urpPNz6g-_qufF-Y1YppcBf0v3Cs" + * } + * @return an existing or a new consumer + */ def getOrCreateConsumerFuture(idToken: String, userId: Box[String]): Box[Consumer] = { val azp = getClaim(name = "azp", idToken = idToken) val iss = getClaim(name = "iss", idToken = idToken) diff --git a/obp-api/src/main/scala/code/model/OAuth.scala b/obp-api/src/main/scala/code/model/OAuth.scala index e6aec6b12..c7169635b 100644 --- a/obp-api/src/main/scala/code/model/OAuth.scala +++ b/obp-api/src/main/scala/code/model/OAuth.scala @@ -289,9 +289,12 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = { - val consumer = Consumer.find(By(Consumer.consumerId, consumerId.getOrElse("None"))) or { - Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.createdByUserId, createdByUserId.getOrElse("None"))) - } + val consumer = + // 1st try represent GatewayLogin usage of this function + Consumer.find(By(Consumer.consumerId, consumerId.getOrElse("None"))) or { + // 2nd try represent OAuth2 usage of this function + Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.createdByUserId, createdByUserId.getOrElse("None"))) + } consumer match { case Full(c) => Full(c) case Failure(msg, t, c) => Failure(msg, t, c) From bb9255f81a4641b109adcfe6b3df730b6b2366f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Fri, 25 Oct 2019 17:42:32 +0200 Subject: [PATCH 7/7] Create consumer implicitly during OAuth2 workflow - extends consuer table --- .../main/scala/code/api/GatewayLogin.scala | 2 ++ obp-api/src/main/scala/code/api/OAuth2.scala | 11 +++++--- .../code/consumer/ConsumerProvider.scala | 28 +++++++++++++++++-- obp-api/src/main/scala/code/model/OAuth.scala | 20 +++++++++++-- .../code/remotedata/RemotedataConsumers.scala | 16 +++++++++-- .../remotedata/RemotedataConsumersActor.scala | 6 ++-- 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/obp-api/src/main/scala/code/api/GatewayLogin.scala b/obp-api/src/main/scala/code/api/GatewayLogin.scala index 703feca28..085a1502b 100755 --- a/obp-api/src/main/scala/code/api/GatewayLogin.scala +++ b/obp-api/src/main/scala/code/api/GatewayLogin.scala @@ -354,6 +354,8 @@ object GatewayLogin extends RestHelper with MdcLoggable { Some(Helpers.randomString(40).toLowerCase), Some(Helpers.randomString(40).toLowerCase), None, + None, + None, Some(true), name = Some(consumerName), appType = None, diff --git a/obp-api/src/main/scala/code/api/OAuth2.scala b/obp-api/src/main/scala/code/api/OAuth2.scala index 052bce4c4..715502d0b 100644 --- a/obp-api/src/main/scala/code/api/OAuth2.scala +++ b/obp-api/src/main/scala/code/api/OAuth2.scala @@ -236,11 +236,11 @@ object OAuth2Login extends RestHelper with MdcLoggable { } } /** - * This function creates a consumer based on "azp", "iss", "name" and "email" fields + * This function creates a consumer based on "azp", "sub", "iss", "name" and "email" fields * Please note that a user must be created before consumer. - * Unique criteria to decide do we create or get a consumer is pair o values: < createdByUserId : azp > i.e. - * We cannot find consumer by createdByUserId and azp => Create - * We can find consumer by createdByUserId and azp => Get + * Unique criteria to decide do we create or get a consumer is pair o values: < sub : azp > i.e. + * We cannot find consumer by sub and azp => Create + * We can find consumer by sub and azp => Get * @param idToken Google's response example: * { * "access_token": "ya29.GluUBg5DflrJciFikW5hqeKEp9r1whWnU5x2JXCm9rKkRMs2WseXX8O5UugFMDsIKuKCZlE7tTm1fMII_YYpvcMX6quyR5DXNHH8Lbx5TrZN__fA92kszHJEVqPc", @@ -255,6 +255,7 @@ object OAuth2Login extends RestHelper with MdcLoggable { def getOrCreateConsumerFuture(idToken: String, userId: Box[String]): Box[Consumer] = { val azp = getClaim(name = "azp", idToken = idToken) val iss = getClaim(name = "iss", idToken = idToken) + val sub = getClaim(name = "sub", idToken = idToken) val email = getClaim(name = "email", idToken = idToken) val name = getClaim(name = "name", idToken = idToken) Consumers.consumers.vend.getOrCreateConsumer( @@ -262,6 +263,8 @@ object OAuth2Login extends RestHelper with MdcLoggable { key = Some(Helpers.randomString(40).toLowerCase), secret = Some(Helpers.randomString(40).toLowerCase), azp = azp, + iss = iss, + sub = sub, Some(true), name = name, appType = None, diff --git a/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala b/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala index 62cb44f74..3d2c17c18 100644 --- a/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala +++ b/obp-api/src/main/scala/code/consumer/ConsumerProvider.scala @@ -33,7 +33,19 @@ trait ConsumersProvider { def createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]] - def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], + azp: Option[String], + iss: Option[String], + sub: Option[String], + isActive: Option[Boolean], + name: Option[String], + appType: Option[AppType], + description: Option[String], + developerEmail: Option[String], + redirectURL: Option[String], + createdByUserId: Option[String]): Box[Consumer] def populateMissingUUIDs(): Boolean } @@ -50,7 +62,19 @@ class RemotedataConsumersCaseClasses { case class createConsumer(key: Option[String], secret: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) case class updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]) - case class getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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], + azp: Option[String], + iss: Option[String], + sub: Option[String], + isActive: Option[Boolean], + name: Option[String], + appType: Option[AppType], + description: Option[String], + developerEmail: Option[String], + redirectURL: Option[String], + createdByUserId: Option[String]) case class populateMissingUUIDs() } diff --git a/obp-api/src/main/scala/code/model/OAuth.scala b/obp-api/src/main/scala/code/model/OAuth.scala index c7169635b..2798a69f2 100644 --- a/obp-api/src/main/scala/code/model/OAuth.scala +++ b/obp-api/src/main/scala/code/model/OAuth.scala @@ -281,6 +281,8 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { key: Option[String], secret: Option[String], azp: Option[String], + iss: Option[String], + sub: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], @@ -293,7 +295,7 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { // 1st try represent GatewayLogin usage of this function Consumer.find(By(Consumer.consumerId, consumerId.getOrElse("None"))) or { // 2nd try represent OAuth2 usage of this function - Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.createdByUserId, createdByUserId.getOrElse("None"))) + Consumer.find(By(Consumer.azp, azp.getOrElse("None")), By(Consumer.sub, sub.getOrElse("None"))) } consumer match { case Full(c) => Full(c) @@ -314,6 +316,14 @@ object MappedConsumersProvider extends ConsumersProvider with MdcLoggable { case Some(v) => c.azp(v) case None => } + iss match { + case Some(v) => c.iss(v) + case None => + } + sub match { + case Some(v) => c.sub(v) + case None => + } isActive match { case Some(v) => c.isActive(v) case None => @@ -420,6 +430,12 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{ object secret extends MappedString(this, 250) object azp extends MappedString(this, 250) { override def defaultValue = null + } + object iss extends MappedString(this, 250) { + override def defaultValue = null + } + object sub extends MappedString(this, 250) { + override def defaultValue = null } object isActive extends MappedBoolean(this){ override def defaultValue = APIUtil.getPropsAsBoolValue("consumers_enabled_by_default", false) @@ -479,7 +495,7 @@ class Consumer extends LongKeyedMapper[Consumer] with CreatedUpdated{ */ object Consumer extends Consumer with MdcLoggable with LongKeyedMetaMapper[Consumer] with CRUDify[Long, Consumer]{ - override def dbIndexes = UniqueIndex(key) :: UniqueIndex(azp, createdByUserId) :: super.dbIndexes + override def dbIndexes = UniqueIndex(key) :: UniqueIndex(azp, sub) :: super.dbIndexes //list all path : /admin/consumer/list override def calcPrefix = List("admin",_dbTableNameLC) diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala b/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala index a23627e87..691cd1d21 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataConsumers.scala @@ -54,8 +54,20 @@ object RemotedataConsumers extends ObpActorInit with ConsumersProvider { def updateConsumerCallLimits(id: Long, perSecond: Option[String], perMinute: Option[String], perHour: Option[String], perDay: Option[String], perWeek: Option[String], perMonth: Option[String]): Future[Box[Consumer]] = (actor ? cc.updateConsumerCallLimits(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth)).mapTo[Box[Consumer]] - def getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture( - (actor ? cc.getOrCreateConsumer(consumerId, key, secret, azp, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]] + def getOrCreateConsumer(consumerId: Option[String], + key: Option[String], + secret: Option[String], + azp: Option[String], + iss: Option[String], + sub: Option[String], + isActive: Option[Boolean], + name: Option[String], + appType: Option[AppType], + description: Option[String], + developerEmail: Option[String], + redirectURL: Option[String], + createdByUserId: Option[String]): Box[Consumer] = getValueFromFuture( + (actor ? cc.getOrCreateConsumer(consumerId, key, secret, azp, iss, sub, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)).mapTo[Box[Consumer]] ) def populateMissingUUIDs(): Boolean = getValueFromFuture( (actor ? cc.populateMissingUUIDs()).mapTo[Boolean] diff --git a/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala b/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala index 418483bbb..8b0f80a84 100644 --- a/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala +++ b/obp-api/src/main/scala/code/remotedata/RemotedataConsumersActor.scala @@ -53,9 +53,9 @@ class RemotedataConsumersActor extends Actor with ObpActorHelper with MdcLoggabl logger.debug("updateConsumerCallLimits(" + id + ", " + perSecond.getOrElse("None")+ ", " + perMinute.getOrElse("None") + ", " + perHour.getOrElse("None") + ", " + perDay.getOrElse("None") + ", " + perWeek.getOrElse("None") + ", " + perMonth.getOrElse("None") + ")") sender ! (mapper.updateConsumerCallLimitsRemote(id, perSecond, perMinute, perHour, perDay, perWeek, perMonth)) - case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[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") + ")") - sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, azp, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)) + case cc.getOrCreateConsumer(consumerId: Option[String], key: Option[String], secret: Option[String], azp: Option[String], iss: Option[String], sub: Option[String], isActive: Option[Boolean], name: Option[String], appType: Option[AppType], description: Option[String], developerEmail: Option[String], redirectURL: Option[String], createdByUserId: Option[String]) => + logger.debug("getOrCreateConsumer(" + consumerId.getOrElse("None") + ", " + "*****" + ", " + "*****" + ", " + azp.getOrElse("None") + ", " + iss.getOrElse("None") + ", " + sub.getOrElse("None") + ", " + name.getOrElse("None") + ", " + appType.getOrElse("None") + ", " + description.getOrElse("None") + ", " + developerEmail.getOrElse("None") + ", " + redirectURL.getOrElse("None") + ", " + createdByUserId.getOrElse("None") + ")") + sender ! (mapper.getOrCreateConsumer(consumerId, key, secret, azp, iss, sub, isActive, name, appType, description, developerEmail, redirectURL, createdByUserId)) case cc.populateMissingUUIDs() => logger.debug("populateMissingUUIDs()")