1616// under the License.
1717package com .cloud .api ;
1818
19+ import java .util .Arrays ;
1920import java .util .HashMap ;
2021import java .util .Map ;
2122
23+ import com .cloud .utils .exception .CloudRuntimeException ;
2224import org .apache .log4j .Logger ;
2325
2426import com .fasterxml .jackson .core .JsonProcessingException ;
3032public class ApiSerializerHelper {
3133 public static final Logger s_logger = Logger .getLogger (ApiSerializerHelper .class .getName ());
3234 private static String token = "/" ;
35+ private static String [] apiPackages = {"com.cloud.agent.api" , "org.apache.cloudstack.api" };
3336
34- public static String toSerializedString (Object result ) {
35- if (result != null ) {
36- Class <?> clz = result .getClass ();
37+ /**
38+ * serialise an object's class to a {@link String}
39+ * @param inputObject
40+ * @return
41+ */
42+ public static String toSerializedString (Object inputObject ) {
43+ if (inputObject != null ) {
44+ Class <?> clz = inputObject .getClass ();
3745 Gson gson = ApiGsonHelper .getBuilder ().create ();
3846
39- if (result instanceof ResponseObject ) {
40- return clz .getName () + token + ((ResponseObject )result ).getObjectName () + token + gson .toJson (result );
47+ if (inputObject instanceof ResponseObject ) {
48+ return clz .getName () + token + ((ResponseObject )inputObject ).getObjectName () + token + gson .toJson (inputObject );
4149 } else {
42- return clz .getName () + token + gson .toJson (result );
50+ return clz .getName () + token + gson .toJson (inputObject );
4351 }
4452 }
4553 return null ;
4654 }
4755
48- public static Object fromSerializedString (String result ) {
56+ /**
57+ * deserialise an {@link Object} from a {@link String}
58+ *
59+ * @param classString the string representation of the {@link Class} instance to create
60+ * @return an {@link Object} of the requested {@link Class} type
61+ */
62+ public static Object fromSerializedString (String classString ) {
4963 try {
50- if (result != null && !result .isEmpty ()) {
51- String [] serializedParts = result .split (token );
64+ if (classString != null && !classString .isEmpty ()) {
65+ String [] serializedParts = classString .split (token );
5266
5367 if (serializedParts .length < 2 ) {
5468 return null ;
5569 }
5670 String clzName = serializedParts [0 ];
71+ validateClassPath (clzName , apiPackages );
5772 String nameField = null ;
5873 String content = null ;
5974 if (serializedParts .length == 2 ) {
6075 content = serializedParts [1 ];
6176 } else {
6277 nameField = serializedParts [1 ];
63- int index = result .indexOf (token + nameField + token );
64- content = result .substring (index + nameField .length () + 2 );
78+ int index = classString .indexOf (token + nameField + token );
79+ content = classString .substring (index + nameField .length () + 2 );
6580 }
6681
6782 Class <?> clz ;
@@ -80,15 +95,43 @@ public static Object fromSerializedString(String result) {
8095 }
8196 return null ;
8297 } catch (RuntimeException e ) {
83- s_logger .error ("Caught runtime exception when doing GSON deserialization on: " + result );
98+ s_logger .error ("Caught runtime exception when doing GSON deserialization on: " + classString );
8499 throw e ;
85100 }
86101 }
87102
88- public static Map <String , Object > fromSerializedStringToMap (String result ) {
103+ /**
104+ * validates that a class is allowed to be deserialised.
105+ *
106+ * TODO move to a more globally accesible util class
107+ * TODO make generic for allow lists
108+ * TODO extend to return the desired class
109+ *
110+ * @param clzName
111+ * @param basePaths
112+ */
113+ private static void validateClassPath (String clzName , String [] basePaths ) {
114+ if (clzName != null ) {
115+ for (String basePath : basePaths ) {
116+ if (clzName .startsWith (basePath )) {
117+ return ;
118+ }
119+ }
120+ }
121+ String packages = Arrays .toString (basePaths );
122+ throw new CloudRuntimeException (String .format ("illegal to load \" %s\" forName, only classes in packages \" %s\" are allowed" , clzName , packages ));
123+ }
124+
125+ /**
126+ * deserialise a map
127+ *
128+ * @param mapRepresentation the {@link String} representation of the {@link Map<>} type
129+ * @return the {@link Map<>} object
130+ */
131+ public static Map <String , Object > fromSerializedStringToMap (String mapRepresentation ) {
89132 Map <String ,Object > objParams = null ;
90133 try {
91- Object obj = fromSerializedString (result );
134+ Object obj = fromSerializedString (mapRepresentation );
92135 if (obj != null ) {
93136 Gson gson = ApiGsonHelper .getBuilder ().create ();
94137 String objJson = gson .toJson (obj );
@@ -101,7 +144,7 @@ public static Map<String, Object> fromSerializedStringToMap(String result) {
101144 }
102145 }
103146 } catch (RuntimeException | JsonProcessingException e ) {
104- s_logger .error ("Caught runtime exception when doing GSON deserialization to map on: " + result , e );
147+ s_logger .error ("Caught runtime exception when doing GSON deserialization to map on: " + mapRepresentation , e );
105148 }
106149
107150 return objParams ;
0 commit comments