summaryrefslogtreecommitdiffstats
path: root/ms/blueprintsprocessor/modules/inbounds/selfservice-api
diff options
context:
space:
mode:
authorJulien Fontaine <julien.fontaine@bell.ca>2020-08-07 09:51:39 -0400
committerJulien Fontaine <julien.fontaine@bell.ca>2020-08-07 09:51:39 -0400
commitbe701b483f4c775285b372bca0cfeb7f0332e931 (patch)
tree37412eb02bd0a836fcc525b6863202b41dff2d63 /ms/blueprintsprocessor/modules/inbounds/selfservice-api
parent4a01363c4634a62946d6f2befe00cbf2d9872d90 (diff)
Kafka Audit Service: Error during sensitive data hiding
Changed behaviour during sensitive data hiding. Instead of looking for every node template defined in the CBA we only check for the ones declared for the current executed workflow. This prevent the issue when you have two independant workflows defined in the same CBA and one of those has a node template using a get_input expression for template-prefix in a component-resource-resolution. If you execute the other workflow audit service was still trying to resolve this expression which was making it fail. Issue-ID: CCSDK-2636 Signed-off-by: Julien Fontaine <julien.fontaine@bell.ca> Change-Id: Ib232c26ebf930917e19e7970e1a56c15e676888f
Diffstat (limited to 'ms/blueprintsprocessor/modules/inbounds/selfservice-api')
-rw-r--r--ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/KafkaPublishAuditService.kt172
1 files changed, 118 insertions, 54 deletions
diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/KafkaPublishAuditService.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/KafkaPublishAuditService.kt
index fca73981e..12cadfa66 100644
--- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/KafkaPublishAuditService.kt
+++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/KafkaPublishAuditService.kt
@@ -17,6 +17,7 @@
package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.node.ArrayNode
import com.fasterxml.jackson.databind.node.ObjectNode
import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
@@ -27,6 +28,8 @@ import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants
import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
import org.onap.ccsdk.cds.controllerblueprints.core.service.PropertyAssignmentService
import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
@@ -40,6 +43,13 @@ import javax.annotation.PostConstruct
/**
* Audit service used to produce execution service input and output message
* sent into dedicated kafka topics.
+ *
+ * @param bluePrintMessageLibPropertyService Service used to instantiate audit service producers
+ * @param blueprintsProcessorCatalogService Service used to get the base path of the current CBA executed
+ *
+ * @property inputInstance Request Kakfa Producer instance
+ * @property outputInstance Response Kakfa Producer instance
+ * @property log Audit Service logger
*/
@ConditionalOnProperty(
name = ["blueprintsprocessor.messageproducer.self-service-api.audit.kafkaEnable"],
@@ -68,9 +78,11 @@ class KafkaPublishAuditService(
* Publish execution input into a kafka topic.
* The correlation UUID is used to link the input to its output.
* Sensitive data within the request are hidden.
+ * @param executionServiceInput Audited BP request
*/
override suspend fun publishExecutionInput(executionServiceInput: ExecutionServiceInput) {
val secureExecutionServiceInput = hideSensitiveData(executionServiceInput)
+ val key = secureExecutionServiceInput.actionIdentifiers.blueprintName
try {
this.inputInstance = this.getInputInstance(INPUT_SELECTOR)
this.inputInstance!!.sendMessage(secureExecutionServiceInput)
@@ -86,32 +98,38 @@ class KafkaPublishAuditService(
* Publish execution output into a kafka topic.
* The correlation UUID is used to link the output to its input.
* A correlation UUID is added to link the input to its output.
+ * @param correlationUUID UUID used to link the audited response to its audited request
+ * @param executionServiceOutput Audited BP response
*/
override suspend fun publishExecutionOutput(correlationUUID: String, executionServiceOutput: ExecutionServiceOutput) {
executionServiceOutput.correlationUUID = correlationUUID
+ val key = executionServiceOutput.actionIdentifiers.blueprintName
try {
this.outputInstance = this.getOutputInstance(OUTPUT_SELECTOR)
this.outputInstance!!.sendMessage(executionServiceOutput)
} catch (e: Exception) {
var errMsg =
- if (e.message != null) "ERROR : $e"
- else "ERROR : Failed to send execution request to Kafka."
+ if (e.message != null) "ERROR : $e"
+ else "ERROR : Failed to send execution request to Kafka."
log.error(errMsg)
}
}
/**
- * Return the input kafka producer instance using a selector.
+ * Return the input kafka producer instance using a [selector] if not already instantiated.
+ * @param selector Selector to retrieve request kafka producer configuration
*/
private fun getInputInstance(selector: String): BlueprintMessageProducerService = inputInstance ?: createInstance(selector)
/**
- * Return the output kafka producer instance using a selector.
+ * Return the output kafka producer instance using a [selector] if not already instantiated.
+ * @param selector Selector to retrieve response kafka producer configuration
*/
private fun getOutputInstance(selector: String): BlueprintMessageProducerService = outputInstance ?: createInstance(selector)
/**
- * Create a kafka producer instance.
+ * Create a kafka producer instance using a [selector].
+ * @param selector Selector to retrieve kafka producer configuration
*/
private fun createInstance(selector: String): BlueprintMessageProducerService {
log.info("Setting up message producer($selector)...")
@@ -119,9 +137,10 @@ class KafkaPublishAuditService(
}
/**
- * Hide sensitive data in the request.
+ * Hide sensitive data in the [executionServiceInput].
* Sensitive data are declared in the resource resolution mapping using
* the property metadata "log-protect" set to true.
+ * @param executionServiceInput BP Execution Request where data needs to be hidden
*/
private suspend fun hideSensitiveData(
executionServiceInput: ExecutionServiceInput
@@ -153,60 +172,105 @@ class KafkaPublishAuditService(
val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(requestId, basePath.toString())
val blueprintContext = blueprintRuntimeService.bluePrintContext()
- /** Looking for node templates defined as component-resource-resolution */
- val nodeTemplates = blueprintContext.nodeTemplates()
- nodeTemplates!!.forEach { nodeTemplate ->
- val nodeTemplateName = nodeTemplate.key
- val nodeTemplateType = blueprintContext.nodeTemplateByName(nodeTemplateName).type
- if (nodeTemplateType == BluePrintConstants.NODE_TEMPLATE_TYPE_COMPONENT_RESOURCE_RESOLUTION) {
- val interfaceName = blueprintContext.nodeTemplateFirstInterfaceName(nodeTemplateName)
- val operationName = blueprintContext.nodeTemplateFirstInterfaceFirstOperationName(nodeTemplateName)
-
- val propertyAssignments: MutableMap<String, JsonNode> =
- blueprintContext.nodeTemplateInterfaceOperationInputs(nodeTemplateName, interfaceName, operationName)
- ?: hashMapOf()
-
- /** Getting values define in artifact-prefix-names */
- val input = executionServiceInput.payload.get("$workflowName-request")
- blueprintRuntimeService.assignWorkflowInputs(workflowName, input)
- val artifactPrefixNamesNode = propertyAssignments[ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES]
- val propertyAssignmentService = PropertyAssignmentService(blueprintRuntimeService)
- val artifactPrefixNamesNodeValue = propertyAssignmentService.resolveAssignmentExpression(
- BluePrintConstants.MODEL_DEFINITION_TYPE_NODE_TEMPLATE,
- nodeTemplateName,
- ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES,
- artifactPrefixNamesNode!!)
-
- val artifactPrefixNames = JacksonUtils.getListFromJsonNode(artifactPrefixNamesNodeValue!!, String::class.java)
-
- /** Storing mapping entries with metadata log-protect set to true */
- val sensitiveParameters: List<String> = artifactPrefixNames
- .map { "$it-mapping" }
- .map { blueprintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, it) }
- .flatMap { JacksonUtils.getListFromJson(it, ResourceAssignment::class.java) }
- .filter { PropertyDefinitionUtils.hasLogProtect(it.property) }
- .map { it.name }
-
- /** Hiding sensitive input parameters from the request */
- var workflowProperties: ObjectNode = clonedExecutionServiceInput.payload
- .path("$workflowName-request")
- .path("$workflowName-properties") as ObjectNode
-
- sensitiveParameters.forEach { sensitiveParameter ->
- if (workflowProperties.has(sensitiveParameter)) {
- workflowProperties.replace(sensitiveParameter, ApplicationConstants.LOG_REDACTED.asJsonPrimitive())
- }
+ val workflowSteps = blueprintContext.workflowByName(workflowName).steps
+ checkNotNull(workflowSteps) { "Failed to get step(s) for workflow($workflowName)" }
+ workflowSteps.forEach { step ->
+ val nodeTemplateName = step.value.target
+ checkNotNull(nodeTemplateName) { "Failed to get node template target for workflow($workflowName), step($step)" }
+ val nodeTemplate = blueprintContext.nodeTemplateByName(nodeTemplateName)
+
+ /** We need to check in his Node Template Dependencies is case of a Node Template DG */
+ if (nodeTemplate.type == BluePrintConstants.NODE_TEMPLATE_TYPE_DG) {
+ val dependencyNodeTemplate = nodeTemplate.properties?.get(BluePrintConstants.PROPERTY_DG_DEPENDENCY_NODE_TEMPLATE) as ArrayNode
+ dependencyNodeTemplate.forEach { dependencyNodeTemplateName ->
+ clonedExecutionServiceInput = hideSensitiveDataFromResourceResolution(
+ blueprintRuntimeService,
+ blueprintContext,
+ clonedExecutionServiceInput,
+ workflowName,
+ dependencyNodeTemplateName.asText()
+ )
}
+ } else {
+ clonedExecutionServiceInput = hideSensitiveDataFromResourceResolution(
+ blueprintRuntimeService,
+ blueprintContext,
+ clonedExecutionServiceInput,
+ workflowName,
+ nodeTemplateName
+ )
}
}
}
} catch (e: Exception) {
- val errMsg = "ERROR : Couldn't hide sensitive data in the execution request."
- log.error(errMsg, e)
- clonedExecutionServiceInput.payload.replace(
- "$workflowName-request",
- "$errMsg $e".asJsonPrimitive())
+ val errMsg = "ERROR : Couldn't hide sensitive data in the execution request."
+ log.error(errMsg, e)
+ clonedExecutionServiceInput.payload.replace(
+ "$workflowName-request",
+ "$errMsg $e".asJsonPrimitive())
}
return clonedExecutionServiceInput
}
+
+ /**
+ * Hide sensitive data in [executionServiceInput] if the given [nodeTemplateName] is a
+ * resource resolution component.
+ * @param blueprintRuntimeService Current blueprint runtime service
+ * @param blueprintContext Current blueprint runtime context
+ * @param executionServiceInput BP Execution Request where data needs to be hidden
+ * @param workflowName Current workflow being executed
+ * @param nodeTemplateName Node template to check for sensitive data
+ * @return [executionServiceInput] with sensitive inputs replaced by a generic string
+ */
+ private suspend fun hideSensitiveDataFromResourceResolution(
+ blueprintRuntimeService: BluePrintRuntimeService<MutableMap<String, JsonNode>>,
+ blueprintContext: BluePrintContext,
+ executionServiceInput: ExecutionServiceInput,
+ workflowName: String,
+ nodeTemplateName: String
+ ): ExecutionServiceInput {
+
+ val nodeTemplate = blueprintContext.nodeTemplateByName(nodeTemplateName)
+ if (nodeTemplate.type == BluePrintConstants.NODE_TEMPLATE_TYPE_COMPONENT_RESOURCE_RESOLUTION) {
+ val interfaceName = blueprintContext.nodeTemplateFirstInterfaceName(nodeTemplateName)
+ val operationName = blueprintContext.nodeTemplateFirstInterfaceFirstOperationName(nodeTemplateName)
+
+ val propertyAssignments: MutableMap<String, JsonNode> =
+ blueprintContext.nodeTemplateInterfaceOperationInputs(nodeTemplateName, interfaceName, operationName)
+ ?: hashMapOf()
+
+ /** Getting values define in artifact-prefix-names */
+ val input = executionServiceInput.payload.get("$workflowName-request")
+ blueprintRuntimeService.assignWorkflowInputs(workflowName, input)
+ val artifactPrefixNamesNode = propertyAssignments[ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES]
+ val propertyAssignmentService = PropertyAssignmentService(blueprintRuntimeService)
+ val artifactPrefixNamesNodeValue = propertyAssignmentService.resolveAssignmentExpression(
+ BluePrintConstants.MODEL_DEFINITION_TYPE_NODE_TEMPLATE,
+ nodeTemplateName,
+ ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES,
+ artifactPrefixNamesNode!!)
+
+ val artifactPrefixNames = JacksonUtils.getListFromJsonNode(artifactPrefixNamesNodeValue!!, String::class.java)
+
+ /** Storing mapping entries with metadata log-protect set to true */
+ val sensitiveParameters: List<String> = artifactPrefixNames
+ .map { "$it-mapping" }
+ .map { blueprintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, it) }
+ .flatMap { JacksonUtils.getListFromJson(it, ResourceAssignment::class.java) }
+ .filter { PropertyDefinitionUtils.hasLogProtect(it.property) }
+ .map { it.name }
+
+ /** Hiding sensitive input parameters from the request */
+ var workflowProperties: ObjectNode = executionServiceInput.payload
+ .path("$workflowName-request")
+ .path("$workflowName-properties") as ObjectNode
+
+ sensitiveParameters.forEach { sensitiveParameter ->
+ if (workflowProperties.has(sensitiveParameter)) {
+ workflowProperties.replace(sensitiveParameter, ApplicationConstants.LOG_REDACTED.asJsonPrimitive())
+ }
+ }
+ }
+ return executionServiceInput
+ }
}