Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ import code.metadata.tags.MappedTag
import code.metadata.transactionimages.MappedTransactionImage
import code.metadata.wheretags.MappedWhereTag
import code.methodrouting.MethodRouting
import code.metrics.{MappedConnectorMetric, MappedMetric, MetricArchive}
import code.metrics.{MappedConnectorTrace, MappedConnectorMetric, MappedMetric, MetricArchive}
import code.migration.MigrationScriptLog
import code.model._
import code.model.dataAccess._
Expand Down Expand Up @@ -1162,6 +1162,7 @@ object ToSchemify {
MapperAccountHolders,
MappedEntitlement,
MappedConnectorMetric,
MappedConnectorTrace,
MappedExpectedChallengeAnswer,
MappedEntitlementRequest,
MappedScope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6077,6 +6077,31 @@ object SwaggerDefinitionsJSON {
description = descriptionExample.value
)

lazy val connectorTraceJsonV600 = ConnectorTraceJsonV600(
connector_trace_id = 1,
correlation_id = "12345-abcde",
connector_name = "mapped",
function_name = "getBanks",
bank_id = "gh.29.uk",
outbound_message = """{"bankId":"gh.29.uk"}""",
inbound_message = """{"status":"Success","data":[{"bankId":"gh.29.uk","shortName":"Test Bank"}]}""",
date = DateWithDayExampleObject,
duration = 150,
is_successful = true,
user_id = "9ca9a7e4-6d02-40e3-a129-0b2bf89de9f0",
http_verb = "GET",
url = "/obp/v6.0.0/banks"
)

lazy val connectorTracesJsonV600 = ConnectorTracesJsonV600(
connector_traces = List(connectorTraceJsonV600)
)

lazy val configPropsJsonV600 = ListResult(
"config_props",
List(ConfigPropJsonV600("connector", "star"), ConfigPropJsonV600("write_metrics", "true"))
)

// HOLD sample (V600)
lazy val transactionRequestBodyHoldJsonV600 = TransactionRequestBodyHoldJsonV600(
value = amountOfMoneyJsonV121,
Expand Down
30 changes: 30 additions & 0 deletions obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3932,6 +3932,36 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
proPairs
}

def getConfigPropsPairs: List[(String, String)] = {
val filepath = this.getClass.getResource("/props/sample.props.template").getPath
val bufferedSource: BufferedSource = scala.io.Source.fromFile(filepath)
try {
val keys: List[String] = (for {
line <- bufferedSource.getLines.toList
trimmed = line.trim
if trimmed.nonEmpty
if !trimmed.startsWith("webui_") && !trimmed.startsWith("#webui_")
cleaned = if (trimmed.startsWith("#")) trimmed.substring(1).trim else trimmed
if cleaned.contains("=") && !cleaned.startsWith("#")
parts = cleaned.split("=", 2)
key = parts(0).trim
if key.nonEmpty
} yield key).distinct
keys.map { key =>
(key, getPropsValue(key).openOr(""))
}
} finally {
bufferedSource.close()
}
}

private val sensitivePropsPatterns = List("password", "secret", "passphrase", "credential", "token_secret")

def maskSensitivePropValue(key: String, value: String): String = {
if (sensitivePropsPatterns.exists(p => key.toLowerCase.contains(p)) && value.nonEmpty) "****"
else value
}

/**
* This function is used to centralize generation of UUID values
* @return UUID as a String value
Expand Down
6 changes: 6 additions & 0 deletions obp-api/src/main/scala/code/api/util/ApiRole.scala
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,12 @@ object ApiRole extends MdcLoggable{
case class CanGetConnectorMetrics(requiresBankId: Boolean = false) extends ApiRole
lazy val canGetConnectorMetrics = CanGetConnectorMetrics()

case class CanGetConnectorTrace(requiresBankId: Boolean = false) extends ApiRole
lazy val canGetConnectorTrace = CanGetConnectorTrace()

case class CanGetConfigProps(requiresBankId: Boolean = false) extends ApiRole
lazy val canGetConfigProps = CanGetConfigProps()

case class CanDeleteEntitlementRequestsAtAnyBank(requiresBankId: Boolean = false) extends ApiRole
lazy val canDeleteEntitlementRequestsAtAnyBank = CanDeleteEntitlementRequestsAtAnyBank()

Expand Down
111 changes: 108 additions & 3 deletions obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600}
import code.api.v6_0_0.OBPAPI6_0_0
import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider}
import code.metrics.{APIMetrics, ConnectorCountsRedis}
import code.metrics.{APIMetrics, ConnectorCountsRedis, ConnectorTraceProvider}
import code.bankconnectors.{Connector, LocalMappedConnectorInternal}
import code.bankconnectors.storedprocedure.StoredProcedureUtils
import code.bankconnectors.LocalMappedConnectorInternal._
Expand Down Expand Up @@ -4756,7 +4756,7 @@ trait APIMethods600 {
implementedInApiVersion,
nameOf(resetPasswordUrl),
"POST",
"/management/user/reset-password-url",
"/users/password-reset",
"Create Password Reset URL and Send Email",
s"""Create a password reset URL for a user and automatically send it via email.
|
Expand Down Expand Up @@ -4799,7 +4799,7 @@ trait APIMethods600 {
)

lazy val resetPasswordUrl: OBPEndpoint = {
case "management" :: "user" :: "reset-password-url" :: Nil JsonPost json -> _ => {
case "users" :: "password-reset" :: Nil JsonPost json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- authenticatedAccess(cc)
Expand Down Expand Up @@ -8687,6 +8687,111 @@ trait APIMethods600 {
}
}

staticResourceDocs += ResourceDoc(
getConnectorTraces,
implementedInApiVersion,
nameOf(getConnectorTraces),
"GET",
"/management/connector/traces",
"Get Connector Traces",
s"""Get connector traces which capture the full outbound/inbound messages for each connector call.
|
|This endpoint requires the CanGetConnectorTrace role.
|
|Connector tracing must be enabled via the write_connector_trace=true property.
|
|Filters Part 1.*filtering* parameters to GET /management/connector/traces
|
|Should be able to filter on the following fields:
|
|eg: /management/connector/traces?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
|
|1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString
|
|2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString
|
|3 limit (for pagination: defaults to 1000) eg:limit=2000
|
|4 offset (for pagination: zero index, defaults to 0) eg: offset=10
|
|5 connector_name (if null ignore)
|
|6 function_name (if null ignore)
|
|7 correlation_id (if null ignore)
|
|8 bank_id (if null ignore)
|
|9 user_id (if null ignore)
|
|Authentication is Required.
|
|""".stripMargin,
EmptyBody,
connectorTracesJsonV600,
List(
InvalidDateFormat,
UnknownError
),
List(apiTagMetric, apiTagApi),
Some(List(canGetConnectorTrace)))

lazy val getConnectorTraces: OBPEndpoint = {
case "management" :: "connector" :: "traces" :: Nil JsonGet _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConnectorTrace, callContext)
httpParams <- NewStyle.function.extractHttpParamsFromUrl(cc.url)
(obpQueryParams, callContext) <- createQueriesByHttpParamsFuture(httpParams, callContext)
traces <- Future(ConnectorTraceProvider.getAllConnectorTraces(obpQueryParams))
} yield {
(JSONFactory600.createConnectorTracesJsonV600(traces), HttpCode.`200`(callContext))
}
}
}

staticResourceDocs += ResourceDoc(
getConfigProps,
implementedInApiVersion,
nameOf(getConfigProps),
"GET",
"/management/config-props",
"Get Config Props",
s"""Get the configuration properties (non-WebUI) and their runtime values.
|
|This endpoint reads all property keys from the sample.props.template file
|(excluding webui_ properties) and returns their current runtime values.
|
|Sensitive properties (containing password, secret, passphrase, credential, token_secret)
|will have their values masked as ****.
|
|Authentication is Required.
|
|""".stripMargin,
EmptyBody,
configPropsJsonV600,
List(
UnknownError
),
List(apiTagApi),
Some(List(canGetConfigProps)))

lazy val getConfigProps: OBPEndpoint = {
case "management" :: "config-props" :: Nil JsonGet _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetConfigProps, callContext)
configProps = getConfigPropsPairs.map { case (key, value) =>
ConfigPropJsonV600(key, maskSensitivePropValue(key, value))
}
} yield {
(ListResult("config_props", configProps), HttpCode.`200`(callContext))
}
}
}

}
}

Expand Down
45 changes: 45 additions & 0 deletions obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package code.api.v6_0_0

import code.api.util.APIUtil.stringOrNull
import code.metrics.MappedConnectorTrace
import code.api.util.RateLimitingPeriod.LimitCallPeriod
import code.api.util._
import code.api.v1_2_1.{AccountHolderJSON, BankRoutingJsonV121, OtherAccountMetadataJSON, TransactionDetailsJSON, TransactionMetadataJSON}
Expand Down Expand Up @@ -817,6 +818,28 @@ case class ApiProductAttributeResponseJsonV600(
is_active: Option[Boolean]
)

case class ConnectorTraceJsonV600(
connector_trace_id: Long,
correlation_id: String,
connector_name: String,
function_name: String,
bank_id: String,
outbound_message: String,
inbound_message: String,
date: Date,
duration: Long,
is_successful: Boolean,
user_id: String,
http_verb: String,
url: String
)

case class ConnectorTracesJsonV600(
connector_traces: List[ConnectorTraceJsonV600]
)

case class ConfigPropJsonV600(name: String, value: String)

object JSONFactory600 extends CustomJsonFormats with MdcLoggable {

def createRedisCallCountersJson(
Expand Down Expand Up @@ -2085,4 +2108,26 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
ApiProductsJsonV600(products.map(p => createApiProductJsonV600(p, None)))
}

def createConnectorTraceJsonV600(trace: MappedConnectorTrace): ConnectorTraceJsonV600 = {
ConnectorTraceJsonV600(
connector_trace_id = trace.id.get,
correlation_id = trace.correlationId.get,
connector_name = trace.connectorName.get,
function_name = trace.functionName.get,
bank_id = trace.bankId.get,
outbound_message = trace.outboundMessage.get,
inbound_message = trace.inboundMessage.get,
date = trace.date.get,
duration = trace.duration.get,
is_successful = trace.isSuccessful.get,
user_id = trace.userId.get,
http_verb = trace.httpVerb.get,
url = trace.url.get
)
}

def createConnectorTracesJsonV600(traces: List[MappedConnectorTrace]): ConnectorTracesJsonV600 = {
ConnectorTracesJsonV600(traces.map(createConnectorTraceJsonV600))
}

}
Loading
Loading