summaryrefslogtreecommitdiffstats
path: root/runtime-acm
diff options
context:
space:
mode:
Diffstat (limited to 'runtime-acm')
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcmParameters.java4
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtils.java147
-rw-r--r--runtime-acm/src/main/resources/application.yaml3
-rw-r--r--runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtilTest.java6
-rw-r--r--runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/util/CommonTestData.java5
-rw-r--r--runtime-acm/src/test/resources/providers/AcDefinitionEncryptTest.yaml27
-rw-r--r--runtime-acm/src/test/resources/providers/AcInstantiateEncryptTest.json15
7 files changed, 172 insertions, 35 deletions
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcmParameters.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcmParameters.java
index 554edea32..becad02df 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcmParameters.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/parameters/AcmParameters.java
@@ -35,8 +35,6 @@ public class AcmParameters {
private String toscaCompositionName = "org.onap.policy.clamp.acm.AutomationComposition";
- private String passPhrase;
-
- private String salt;
+ private boolean enableEncryption = false;
}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtils.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtils.java
index 565adb02d..f7988ea1a 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtils.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtils.java
@@ -29,7 +29,12 @@ import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Base64;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@@ -44,7 +49,14 @@ import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeEx
import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaSchemaDefinition;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
@@ -62,7 +74,9 @@ public class EncryptionUtils {
private static final int IV_LENGTH = 12;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private final String passPhrase;
- private final String salt;
+ private final boolean encryptionEnabled;
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(EncryptionUtils.class);
private static byte[] generateIV() {
@@ -76,8 +90,8 @@ public class EncryptionUtils {
* @param acRuntimeParameterGroup acRuntimeParameterGroup
*/
public EncryptionUtils(AcRuntimeParameterGroup acRuntimeParameterGroup) {
- this.passPhrase = acRuntimeParameterGroup.getAcmParameters().getPassPhrase();
- this.salt = acRuntimeParameterGroup.getAcmParameters().getSalt();
+ this.passPhrase = UUID.nameUUIDFromBytes("encrypt".getBytes()).toString();
+ this.encryptionEnabled = acRuntimeParameterGroup.getAcmParameters().isEnableEncryption();
}
/**
@@ -85,7 +99,7 @@ public class EncryptionUtils {
* @return boolean result
*/
public boolean encryptionEnabled() {
- return passPhrase != null && salt != null;
+ return encryptionEnabled;
}
@@ -97,17 +111,32 @@ public class EncryptionUtils {
public void findAndEncryptSensitiveData(AutomationCompositionDefinition acDefinition,
AutomationComposition automationComposition) {
try {
+ var acNodeTypes = Optional.ofNullable(acDefinition.getServiceTemplate().getNodeTypes()).map(Map::values)
+ .orElse(Collections.emptyList());
+ var acDataTypes = Optional.ofNullable(acDefinition.getServiceTemplate().getDataTypes()).map(Map::values)
+ .orElse(Collections.emptyList());
+ var nodeTemplates = Optional.ofNullable(acDefinition.getServiceTemplate().getToscaTopologyTemplate())
+ .map(ToscaTopologyTemplate::getNodeTemplates)
+ .map(Map::values).orElse(Collections.emptyList());
+
for (var acInstanceElement: automationComposition.getElements().values()) {
- var sensitiveProperties = findSensitiveElementFields(acDefinition, acInstanceElement);
+ var sensitiveProperties = filterSensitiveProperties(acInstanceElement, acNodeTypes, acDataTypes,
+ nodeTemplates);
+ LOGGER.debug("Sensitive properties for the element {} : {}",
+ acInstanceElement.getId(), sensitiveProperties);
for (var property : sensitiveProperties) {
var elementProperties = acInstanceElement.getProperties();
var sensitiveVal = elementProperties.get(property.getName());
- if (sensitiveVal instanceof String sensitiveStr && !sensitiveStr.startsWith(MARKER)) {
+ if (sensitiveVal == null) {
+ encryptNested(property, elementProperties);
+ } else if (sensitiveVal instanceof String sensitiveStr && !sensitiveStr.startsWith(MARKER)) {
var encryptedVal = encrypt(sensitiveStr);
elementProperties.put(property.getName(), encryptedVal);
+ LOGGER.debug("Property {} is successfully encrypted", property.getName());
}
}
}
+
} catch (Exception e) {
throw new AutomationCompositionRuntimeException(Response.Status.fromStatusCode(500),
"Failed to encrypt instance field ", e);
@@ -127,6 +156,9 @@ public class EncryptionUtils {
if (propertyVal instanceof String propertyValStr && propertyValStr.startsWith(MARKER)) {
var decryptedVal = decrypt(propertyValStr);
acInstanceElement.getProperties().put(property.getKey(), decryptedVal);
+ LOGGER.debug("Property {} is successfully decrypted", property.getKey());
+ } else {
+ decryptNested(propertyVal);
}
}
}
@@ -136,34 +168,117 @@ public class EncryptionUtils {
}
}
+ private void decryptNested(Object propertyVal) throws InvalidAlgorithmParameterException, IllegalBlockSizeException,
+ NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException, InvalidKeySpecException,
+ InvalidKeyException {
+ if (propertyVal instanceof List<?> listVal) {
+ for (var listEntry : listVal) {
+ if (listEntry instanceof Map<?, ?> tempMap) {
+ decryptNestedMap(tempMap);
+ }
+ }
+ } else if (propertyVal instanceof Map<?, ?> tempMap) {
+ decryptNestedMap(tempMap);
+ }
+ }
+
+ private void decryptNestedMap(Map<?, ?> tempMap) throws InvalidAlgorithmParameterException,
+ IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException,
+ InvalidKeySpecException, InvalidKeyException {
+ @SuppressWarnings("unchecked")
+ var nestedMap = (Map<Object, Object>) tempMap;
+ for (var prop : nestedMap.entrySet()) {
+ if (prop.getValue() instanceof String nestedStr && nestedStr.startsWith(MARKER)) {
+ var encryptedVal = decrypt(nestedStr);
+ nestedMap.put(prop.getKey(), encryptedVal);
+ LOGGER.debug("Property {} is successfully decrypted", prop.getKey());
+ }
+ }
+ }
+
+ private void encryptNested(ToscaProperty property, Map<?, ?> properties)
+ throws InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException,
+ BadPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
+ // Iterate over nested maps to check if the property exists inside them
+ for (var mapEntry : properties.entrySet()) {
+ if (mapEntry.getValue() instanceof List<?> listVal) {
+ for (var listEntry : listVal) {
+ if (listEntry instanceof Map<?, ?> tempMap) {
+ encryptNestedMaps(property, tempMap);
+ }
+ }
+ } else if (mapEntry.getValue() instanceof Map<?, ?> tempMap) {
+ encryptNestedMaps(property, tempMap);
+ }
+ }
+
+ }
+
+ private void encryptNestedMaps(ToscaProperty property, Map<?, ?> tempMap) throws InvalidAlgorithmParameterException,
+ IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException,
+ InvalidKeySpecException, InvalidKeyException {
+ @SuppressWarnings("unchecked")
+ var nestedMap = (Map<Object, Object>) tempMap;
+ var nestedValue = nestedMap.get(property.getName());
+ if (nestedValue instanceof String nestedStr && !nestedStr.startsWith(MARKER)) {
+ var encryptedVal = encrypt(nestedStr);
+ nestedMap.put(property.getName(), encryptedVal);
+ LOGGER.debug("Property {} is successfully encrypted", property.getName());
+ }
+ }
+
- private List<ToscaProperty> findSensitiveElementFields(AutomationCompositionDefinition acDefinition,
- AutomationCompositionElement acInstanceElement) {
+ private List<ToscaProperty> filterSensitiveProperties(AutomationCompositionElement acInstanceElement,
+ Collection<ToscaNodeType> nodeTypes,
+ Collection<ToscaDataType> dataTypes,
+ Collection<ToscaNodeTemplate> nodeTemplates) {
List<ToscaProperty> sensitiveProperties = new ArrayList<>();
// Fetch the node template element
- var acDefElementOpt = acDefinition.getServiceTemplate().getToscaTopologyTemplate().getNodeTemplates()
- .values().stream().filter(acDefElement -> acDefElement.getName()
+ var acDefElementOpt = nodeTemplates.stream().filter(acDefElement -> acDefElement.getName()
.equals(acInstanceElement.getDefinition().getName())).findFirst();
// Fetch node type
if (acDefElementOpt.isPresent()) {
- var toscaNodeTypeOpt = acDefinition.getServiceTemplate().getNodeTypes().values().stream()
- .filter(toscaNodeType -> toscaNodeType.getName()
+ var toscaNodeTypeOpt = nodeTypes.stream().filter(toscaNodeType -> toscaNodeType.getName()
.equals(acDefElementOpt.get().getType())).findFirst();
- toscaNodeTypeOpt.ifPresent(toscaNodeType -> toscaNodeType.getProperties().values()
- .stream().filter(property -> property.getMetadata() != null
- && property.getMetadata().containsKey(SENSITIVE_METADATA))
- .forEach(sensitiveProperties::add));
+ if (toscaNodeTypeOpt.isPresent()) {
+ toscaNodeTypeOpt.get().getProperties().values().stream()
+ .filter(this::isSensitiveMetadata)
+ .forEach(sensitiveProperties::add);
+
+ for (var property : toscaNodeTypeOpt.get().getProperties().values()) {
+ dataTypes.stream()
+ .filter(datatype -> isDataTypeRef(property, datatype))
+ .flatMap(dataType -> dataType.getProperties().values().stream())
+ .filter(this::isSensitiveMetadata)
+ .forEach(sensitiveProperties::add);
+ }
+ }
}
return sensitiveProperties;
}
+ private boolean isSensitiveMetadata(ToscaProperty property) {
+ if (property.getMetadata() == null) {
+ return false;
+ }
+ var metadataValue = property.getMetadata().get(SENSITIVE_METADATA);
+ return "true".equals(metadataValue);
+ }
+
+ private boolean isDataTypeRef(ToscaProperty property, ToscaDataType dataType) {
+ var dataTypeName = dataType.getDefinedName();
+ var propertyEntity = Optional.ofNullable(property.getEntrySchema()).map(ToscaSchemaDefinition::getType);
+ return dataTypeName.equals(property.getType()) || dataTypeName.equals(propertyEntity.orElse(null));
+ }
+
private SecretKey getSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
var factory = SecretKeyFactory.getInstance(PBK_ALGORITHM);
+ var salt = "salt";
var spec = new PBEKeySpec(passPhrase.toCharArray(), salt.getBytes(), 65536, 256);
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
}
diff --git a/runtime-acm/src/main/resources/application.yaml b/runtime-acm/src/main/resources/application.yaml
index 247cd2420..59d1aa5df 100644
--- a/runtime-acm/src/main/resources/application.yaml
+++ b/runtime-acm/src/main/resources/application.yaml
@@ -62,8 +62,7 @@ runtime:
acmParameters:
toscaElementName: org.onap.policy.clamp.acm.AutomationCompositionElement
toscaCompositionName: org.onap.policy.clamp.acm.AutomationComposition
- passPhrase: 1234AbCEncryptionPassPhrase
- salt: runtimeFixedSalt
+ enableEncryption: true
management:
endpoints:
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtilTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtilTest.java
index ae6066ae5..7ad8b7169 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtilTest.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/main/utils/EncryptionUtilTest.java
@@ -53,16 +53,18 @@ class EncryptionUtilTest {
void testEncryptAcInstanceProperties() {
var automationComposition =
InstantiationUtils.getAutomationCompositionFromResource(INSTANTIATE_JSON, "Crud");
- var encryptionUtils = new EncryptionUtils(CommonTestData.getEncryptionParamaterGroup());
+ var encryptionUtils = new EncryptionUtils(CommonTestData.getEncryptionParameterGroup());
assertTrue(encryptionUtils.encryptionEnabled());
assertDoesNotThrow(()
-> {
assert automationComposition != null;
encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition);
});
+
+ var encryptionUtil2 = new EncryptionUtils(CommonTestData.getEncryptionParameterGroup());
assertDoesNotThrow(() -> {
assert automationComposition != null;
- encryptionUtils.findAndDecryptSensitiveData(automationComposition);
+ encryptionUtil2.findAndDecryptSensitiveData(automationComposition);
});
}
diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/util/CommonTestData.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/util/CommonTestData.java
index 0392596ce..4762681a0 100644
--- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/util/CommonTestData.java
+++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/util/CommonTestData.java
@@ -170,10 +170,9 @@ public class CommonTestData {
*
* @return a new AutomationCompositionDefinition
*/
- public static AcRuntimeParameterGroup getEncryptionParamaterGroup() {
+ public static AcRuntimeParameterGroup getEncryptionParameterGroup() {
var acRuntimeParameterGroup = getTestParamaterGroup();
- acRuntimeParameterGroup.getAcmParameters().setSalt("randomSalt");
- acRuntimeParameterGroup.getAcmParameters().setPassPhrase("randomPhrase");
+ acRuntimeParameterGroup.getAcmParameters().setEnableEncryption(true);
return acRuntimeParameterGroup;
}
diff --git a/runtime-acm/src/test/resources/providers/AcDefinitionEncryptTest.yaml b/runtime-acm/src/test/resources/providers/AcDefinitionEncryptTest.yaml
index 0e9372876..416af183f 100644
--- a/runtime-acm/src/test/resources/providers/AcDefinitionEncryptTest.yaml
+++ b/runtime-acm/src/test/resources/providers/AcDefinitionEncryptTest.yaml
@@ -27,6 +27,25 @@ data_types:
version:
type: string
required: true
+ org.onap.datatypes.policy.clamp.acm.httpAutomationCompositionElement.ConfigurationEntity:
+ version: 1.0.0
+ derived_from: tosca.datatypes.Root
+ properties:
+ configurationEntityId:
+ type: onap.datatypes.ToscaConceptIdentifier
+ required: true
+ description: The name and version of a Configuration Entity to be handled
+ by the HTTP Automation Composition Element
+ restSequence:
+ type: list
+ entry_schema:
+ type: org.onap.datatypes.policy.clamp.acm.httpAutomationCompositionElement.RestRequest
+ type_version: 1.0.0
+ description: A sequence of REST commands to send to the REST endpoint
+ k8s-secret:
+ type: String
+ metadata:
+ sensitive: true
node_types:
org.onap.policy.clamp.acm.Participant:
@@ -90,7 +109,7 @@ node_types:
type: String
metadata:
sensitive: true
- credential:
+ secret:
type: String
metadata:
sensitive: true
@@ -106,11 +125,9 @@ node_types:
description: HTTP headers to send on REST requests
configurationEntities:
type: map
- required: true
entry_schema:
- type: map
- metadata:
- sensitive: true
+ type: org.onap.datatypes.policy.clamp.acm.httpAutomationCompositionElement.ConfigurationEntity
+ required: true
description: The configuration entities the Automation Composition Element is managing and their associated REST requests
diff --git a/runtime-acm/src/test/resources/providers/AcInstantiateEncryptTest.json b/runtime-acm/src/test/resources/providers/AcInstantiateEncryptTest.json
index acf2a9b16..896a8b6c9 100644
--- a/runtime-acm/src/test/resources/providers/AcInstantiateEncryptTest.json
+++ b/runtime-acm/src/test/resources/providers/AcInstantiateEncryptTest.json
@@ -12,7 +12,7 @@
},
"description": "Starter Automation Composition Element for the Demo",
"properties": {
- "credential": "mycred1",
+ "secret": "mysecret1",
"password": "mypass1",
"baseUrl": "http://address:30800",
"httpHeaders": {
@@ -37,9 +37,15 @@
"expectedResponse": 201
}
],
+ "k8s-secret": "valueToEncrypt",
"myParameterToUpdate": "text1"
}
- ]
+ ],
+ "customProperty": {
+ "name": "test",
+ "k8s-secret": "customValueToEncrypt"
+ }
+
}
},
"709c62b3-8918-41b9-a747-d21eb79c6c35": {
@@ -52,7 +58,7 @@
"properties": {
"baseUrl": "http://address:30801",
"password": "mypass2",
- "credential": "mycred2",
+ "secret": "secret2",
"httpHeaders": {
"Content-Type": "application/json",
"Authorization": "Basic YWNtVXNlcjp6YiFYenRHMzQ="
@@ -75,7 +81,8 @@
"expectedResponse": 201
}
],
- "myParameterToUpdate": "text2"
+ "myParameterToUpdate": "text2",
+ "k8s-secret": "valueToEncrypt2"
}
]
}