1616// under the License.
1717package com .cloud .api ;
1818
19+ import java .util .Arrays ;
1920import java .util .HashMap ;
2021import java .util .Map ;
2122
2223import org .apache .logging .log4j .Logger ;
2324import org .apache .logging .log4j .LogManager ;
2425
26+ import com .cloud .utils .exception .CloudRuntimeException ;
27+
2528import com .fasterxml .jackson .core .JsonProcessingException ;
2629import com .fasterxml .jackson .databind .ObjectMapper ;
2730import com .google .gson .Gson ;
3134public 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