Skip to content

Commit eaeb853

Browse files
DaanHooglandDaan Hoogland
authored andcommitted
validate packages of classes to load
1 parent e4414d1 commit eaeb853

File tree

1 file changed

+59
-15
lines changed

1 file changed

+59
-15
lines changed

server/src/main/java/com/cloud/api/ApiSerializerHelper.java

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616
// under the License.
1717
package com.cloud.api;
1818

19+
import java.util.Arrays;
1920
import java.util.HashMap;
2021
import java.util.Map;
2122

2223
import org.apache.logging.log4j.Logger;
2324
import org.apache.logging.log4j.LogManager;
2425

26+
import com.cloud.utils.exception.CloudRuntimeException;
27+
2528
import com.fasterxml.jackson.core.JsonProcessingException;
2629
import com.fasterxml.jackson.databind.ObjectMapper;
2730
import com.google.gson.Gson;
@@ -31,38 +34,51 @@
3134
public class ApiSerializerHelper {
3235
protected static Logger LOGGER = LogManager.getLogger(ApiSerializerHelper.class);
3336
private static String token = "/";
37+
private static String[] apiPackages = {"com.cloud.agent.api", "org.apache.cloudstack.api"};
3438

35-
public static String toSerializedString(Object result) {
36-
if (result != null) {
37-
Class<?> clz = result.getClass();
39+
/**
40+
* serialise an object's class to a {@link String}
41+
* @param inputObject
42+
* @return
43+
*/
44+
public static String toSerializedString(Object inputObject) {
45+
if (inputObject != null) {
46+
Class<?> clz = inputObject.getClass();
3847
Gson gson = ApiGsonHelper.getBuilder().create();
3948

40-
if (result instanceof ResponseObject) {
41-
return clz.getName() + token + ((ResponseObject)result).getObjectName() + token + gson.toJson(result);
49+
if (inputObject instanceof ResponseObject) {
50+
return clz.getName() + token + ((ResponseObject)inputObject).getObjectName() + token + gson.toJson(inputObject);
4251
} else {
43-
return clz.getName() + token + gson.toJson(result);
52+
return clz.getName() + token + gson.toJson(inputObject);
4453
}
4554
}
4655
return null;
4756
}
4857

49-
public static Object fromSerializedString(String result) {
58+
/**
59+
* deserialise an {@link Object} from a {@link String}
60+
*
61+
* @param classString the string representation of the {@link Class} instance to create
62+
* @return an {@link Object} of the requested {@link Class} type
63+
*/
64+
public static Object fromSerializedString(String classString) {
5065
try {
51-
if (result != null && !result.isEmpty()) {
52-
String[] serializedParts = result.split(token);
66+
if (classString != null && !classString.isEmpty()) {
67+
String[] serializedParts = classString.split(token);
5368

5469
if (serializedParts.length < 2) {
5570
return null;
5671
}
5772
String clzName = serializedParts[0];
73+
validateClassPath(clzName, apiPackages);
5874
String nameField = null;
5975
String content = null;
6076
if (serializedParts.length == 2) {
6177
content = serializedParts[1];
6278
} else {
6379
nameField = serializedParts[1];
64-
int index = result.indexOf(token + nameField + token);
65-
content = result.substring(index + nameField.length() + 2);
80+
int index = classString.indexOf(token + nameField + token);
81+
content = classString.substring(index + nameField.length() + 2);
6682
}
6783

6884
Class<?> clz;
@@ -81,15 +97,43 @@ public static Object fromSerializedString(String result) {
8197
}
8298
return null;
8399
} catch (RuntimeException e) {
84-
LOGGER.error("Caught runtime exception when doing GSON deserialization on: " + result);
100+
LOGGER.error("Caught runtime exception when doing GSON deserialization on: " + classString);
85101
throw e;
86102
}
87103
}
88104

89-
public static Map<String, Object> fromSerializedStringToMap(String result) {
105+
/**
106+
* validates that a class is allowed to be deserialised.
107+
*
108+
* TODO move to a more globally accesible util class
109+
* TODO make generic for allow lists
110+
* TODO extend to return the desired class
111+
*
112+
* @param clzName
113+
* @param basePaths
114+
*/
115+
private static void validateClassPath(String clzName, String[] basePaths) {
116+
if (clzName != null) {
117+
for (String basePath : basePaths) {
118+
if (clzName.startsWith(basePath)) {
119+
return;
120+
}
121+
}
122+
}
123+
String packages = Arrays.toString(basePaths);
124+
throw new CloudRuntimeException(String.format("illegal to load \"%s\" forName, only classes in packages \"%s\" are allowed", clzName, packages));
125+
}
126+
127+
/**
128+
* deserialise a map
129+
*
130+
* @param mapRepresentation the {@link String} representation of the {@link Map<>} type
131+
* @return the {@link Map<>} object
132+
*/
133+
public static Map<String, Object> fromSerializedStringToMap(String mapRepresentation) {
90134
Map<String,Object> objParams = null;
91135
try {
92-
Object obj = fromSerializedString(result);
136+
Object obj = fromSerializedString(mapRepresentation);
93137
if (obj != null) {
94138
Gson gson = ApiGsonHelper.getBuilder().create();
95139
String objJson = gson.toJson(obj);
@@ -102,7 +146,7 @@ public static Map<String, Object> fromSerializedStringToMap(String result) {
102146
}
103147
}
104148
} catch (RuntimeException | JsonProcessingException e) {
105-
LOGGER.error("Caught runtime exception when doing GSON deserialization to map on: " + result, e);
149+
LOGGER.error("Caught runtime exception when doing GSON deserialization to map on: " + mapRepresentation, e);
106150
}
107151

108152
return objParams;

0 commit comments

Comments
 (0)