Integrate CryptoUtils into ONAP common 23/97423/6
authorChou, Joseph (jc2555) <jc2555@att.com>
Tue, 22 Oct 2019 13:47:21 +0000 (09:47 -0400)
committerChou, Joseph (jc2555) <jc2555@att.com>
Thu, 24 Oct 2019 13:01:02 +0000 (09:01 -0400)
Update junit to add test cases

Change-Id: If3236853138a05faac5f51a859b935265c14f0d6
Issue-ID: POLICY-1945
Signed-off-by: Chou, Joseph (jc2555) <jc2555@att.com>
utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java [new file with mode: 0644]
utils/src/test/java/org/onap/policy/common/utils/coder/PropertyCoderTest.java [new file with mode: 0644]

diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/PropertyCoder.java
new file mode 100644 (file)
index 0000000..7b3c16d
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP PAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.coder;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+import java.io.Reader;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import lombok.AccessLevel;
+import lombok.Getter;
+
+import org.apache.commons.lang3.StringUtils;
+import org.onap.policy.common.utils.security.CryptoCoder;
+import org.onap.policy.common.utils.security.CryptoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JSON encoder and decoder using the "property" mechanism, which is currently gson.
+ *
+ */
+public class PropertyCoder {
+    /**
+     * Gson object used to encode and decode messages.
+     */
+    @Getter(AccessLevel.PROTECTED)
+    private static final Gson GSON = new Gson();
+
+    /**
+     * Decode json for encrypted password.
+     *
+     * @param json string
+     * @param keyProperty contains property within jsonObject for secretKey
+     * @param clazz class T object
+     * @return a class T object
+     */
+    public <T> T decode(String json, String keyProperty, Class<T> clazz) throws CoderException {
+        JsonElement jsonElement = GSON.fromJson(json, JsonElement.class);
+        return new MyDecoder(jsonElement, keyProperty).decrypt(jsonElement, clazz);
+    }
+
+    public <T> T decode(Reader reader, String keyProperty, Class<T> clazz) throws CoderException {
+        JsonElement jsonElement = GSON.fromJson(reader, JsonElement.class);
+        return new MyDecoder(jsonElement, keyProperty).decrypt(jsonElement, clazz);
+    }
+
+    private static class MyDecoder extends StandardCoder {
+        private CryptoCoder crypto = null;
+
+        MyDecoder(JsonElement jsonElement, String keyProperty) throws CoderException {
+            if (!jsonElement.isJsonObject()) {
+                return;
+            }
+            JsonObject jsonObject = jsonElement.getAsJsonObject();
+            // Use keyProperty from input to retrieve secretKey
+            String secretKey = jsonObject.get(keyProperty).getAsString();
+            if (!StringUtils.isBlank(secretKey)) {
+                crypto = new CryptoUtils(secretKey);
+            }
+        }
+
+        private <T> T decrypt(JsonElement jsonElement, Class<T> clazz) {
+            if (crypto == null) {
+                return fromJson(jsonElement, clazz);
+            }
+            JsonElement newElement = decrypt(jsonElement);
+            return fromJson(newElement, clazz);
+        }
+
+        private JsonElement decrypt(JsonElement jsonElement) {
+            if (jsonElement.isJsonObject()) {
+                return decryptObject(jsonElement.getAsJsonObject());
+            }
+            if (jsonElement.isJsonArray()) {
+                return decryptArray(jsonElement.getAsJsonArray());
+            }
+            if (!jsonElement.getAsJsonPrimitive().isString()) {
+                return jsonElement;
+            }
+            String value = jsonElement.getAsString();
+            if (!value.startsWith("enc:")) {
+                return jsonElement;
+            }
+            if (crypto != null) {
+                value = crypto.decrypt(value);
+            }
+            return new JsonPrimitive(value);
+        }
+
+        private JsonArray decryptArray(JsonArray jsonArray) {
+            if (crypto == null) {
+                return jsonArray;
+            }
+            JsonArray newArray = new JsonArray();
+            for (JsonElement element: jsonArray) {
+                newArray.add(decrypt(element));
+            }
+            return newArray;
+        }
+
+        private JsonObject decryptObject(JsonObject jsonObject) {
+            if (crypto == null) {
+                return jsonObject;
+            }
+            JsonObject newObject = new JsonObject();
+            Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
+            for (Map.Entry<String, JsonElement> entry : entrySet) {
+                String key = entry.getKey();
+                JsonElement jsonElement = decrypt(entry.getValue());
+                newObject.add(key, jsonElement);
+            }
+            return newObject;
+        }
+    }
+}
\ No newline at end of file
diff --git a/utils/src/test/java/org/onap/policy/common/utils/coder/PropertyCoderTest.java b/utils/src/test/java/org/onap/policy/common/utils/coder/PropertyCoderTest.java
new file mode 100644 (file)
index 0000000..8761775
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.coder;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+
+import lombok.Getter;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class PropertyCoderTest {
+    private PropertyCoder propertyCoder = null;
+    private static final String AES_ENCRYPTION_KEY = "aes_encryption_key";
+    private static final String json =
+            ("{'aes_encryption_key':'abcdefghijklmnopqrstuvwxyzabcdef'"
+            + ",'xacml.pdp.rest.password':'enc:YZ8EqzsxIOzIuK416SWAdrv+0cKKkqsQt/NYH9+uxwI='"
+            + ",'xacml.pdp.rest.user':'testpdp'"
+            + ",'xacml.pdp.rest.client.user':'policy'"
+            + ",'xacml.pdp.rest.client.password':'policy'"
+            + ",'xacml.pdp.rest.environment':'TEST'"
+            + ",'servers':[{'name':'server1','port':'10',"
+            + "'pass':'enc:KXIY94KcAapOAAeFbtjQL4kBPB4k+NJfwdP+GpG3LWQ='}"
+            + ",{'name':'server2','port':'20','pass':'plaintext'}]"
+            + "}").replace('\'', '"');
+
+    /**
+     * Creates a standard object, populated with some data.
+     *
+     * @throws Exception if an error occurs
+     */
+    @Before
+    public void setUp() throws Exception {
+        propertyCoder = new PropertyCoder();
+    }
+
+    @Test
+    public void testPropertyCoder() throws CoderException {
+        MyClass data = propertyCoder.decode(json, AES_ENCRYPTION_KEY, MyClass.class);
+        assertEquals("alpha", data.getPdpRestPass());
+        assertEquals("hello", data.servers.get(0).pass);
+        assertEquals("server1", data.servers.get(0).name);
+        assertEquals("10", data.servers.get(0).port);
+        assertEquals("plaintext", data.servers.get(1).pass);
+    }
+
+    @Test
+    public void testPropertyCoderReader() throws CoderException {
+        Reader reader = new StringReader(json);
+        MyClass data = propertyCoder.decode(reader, AES_ENCRYPTION_KEY, MyClass.class);
+        assertEquals("alpha", data.getPdpRestPass());
+        assertEquals("hello", data.servers.get(0).pass);
+        assertEquals("server1", data.servers.get(0).name);
+        assertEquals("10", data.servers.get(0).port);
+        assertEquals("plaintext", data.servers.get(1).pass);
+    }
+
+    @Getter
+    public static class MyClass {
+        @SerializedName("aes_encryption_key")
+        private String key;
+        @SerializedName("xacml.pdp.rest.password")
+        private String pdpRestPass;
+        @SerializedName("xacml.pdp.rest.user")
+        private String pdpRestUser;
+        @SerializedName("xacml.pdp.rest.client.user")
+        private String pdpClientUser;
+        @SerializedName("xacml.pdp.rest.client.password")
+        private String pdpClientPass;
+        @SerializedName("xacml.pdp.rest.environment")
+        private String pdpRestEnv;
+        @SerializedName("servers")
+        private List<ServerClass> servers;
+    }
+
+    public static class ServerClass {
+        private String name;
+        private String port;
+        private String pass;
+    }
+}
\ No newline at end of file