Author: fmui
Date: Fri Jul 8 10:00:20 2016
New Revision: 1751876
URL: http://svn.apache.org/viewvc?rev=1751876&view=rev
Log:
added JSON constraints to protect clients from malicious or buggy servers
Added:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/JSONConstraints.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/json/JSONConstraintsTest.java
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParseException.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParser.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/Yylex.java
Added:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/JSONConstraints.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/JSONConstraints.java?rev=1751876&view=auto
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/JSONConstraints.java
(added)
+++
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/JSONConstraints.java
Fri Jul 8 10:00:20 2016
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.chemistry.opencmis.commons.impl;
+
+public class JSONConstraints {
+
+ private JSONConstraints() {
+ }
+
+ public static final int MAX_OBJECT_SIZE;
+ public static final int MAX_ARRAY_SIZE;
+ public static final int MAX_DEPTH;
+
+ public static final int MAX_OBJECT_SIZE_DEFAULT = 10000;
+ public static final int MAX_ARRAY_SIZE_DEFAULT = 1000000;
+ public static final int MAX_DEPTH_DEFAULT = 200;
+
+ public static final String MAX_OBJECT_SIZE_SYSTEM_PROPERTY =
"org.apache.chemistry.opencmis.JSONConstraints.maxObjectSize";
+ public static final String MAX_ARRAY_SIZE_SYSTEM_PROPERTY =
"org.apache.chemistry.opencmis.JSONConstraints.maxArraySize";
+ public static final String MAX_DEPTH_SYSTEM_PROPERTY =
"org.apache.chemistry.opencmis.JSONConstraints.maxDepth";
+
+ static {
+ int maxObjectSize = MAX_OBJECT_SIZE_DEFAULT;
+ try {
+ String maxObjectSizeStr =
System.getProperty(MAX_OBJECT_SIZE_SYSTEM_PROPERTY);
+ if (maxObjectSizeStr != null) {
+ maxObjectSize = Integer.parseInt(maxObjectSizeStr);
+
+ // check for sane values
+ if (maxObjectSize < 100) {
+ maxObjectSize = MAX_OBJECT_SIZE_DEFAULT;
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ MAX_OBJECT_SIZE = maxObjectSize;
+
+ int maxArraySize = MAX_ARRAY_SIZE_DEFAULT;
+ try {
+ String maxArraySizeStr =
System.getProperty(MAX_ARRAY_SIZE_SYSTEM_PROPERTY);
+ if (maxArraySizeStr != null) {
+ maxArraySize = Integer.parseInt(maxArraySizeStr);
+
+ // check for sane values
+ if (maxArraySize < 1000) {
+ maxArraySize = MAX_ARRAY_SIZE_DEFAULT;
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ MAX_ARRAY_SIZE = maxArraySize;
+
+ int maxDepth = MAX_DEPTH_DEFAULT;
+ try {
+ String maxDepthStr = System.getProperty(MAX_DEPTH_SYSTEM_PROPERTY);
+ if (maxDepthStr != null) {
+ maxDepth = Integer.parseInt(maxDepthStr);
+
+ // check for sane values
+ if (maxDepth < 10) {
+ maxDepth = MAX_DEPTH_DEFAULT;
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ MAX_DEPTH = maxDepth;
+ }
+}
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParseException.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParseException.java?rev=1751876&r1=1751875&r2=1751876&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParseException.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParseException.java
Fri Jul 8 10:00:20 2016
@@ -21,10 +21,10 @@ package org.apache.chemistry.opencmis.co
/**
* ParseException explains why and where the error occurs in source JSON text.
*
- * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and modified
- * for OpenCMIS.)
+ * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and
+ * modified for OpenCMIS.)
*
- * @author FangYidong<[email protected]>
+ * @author FangYidong<[email protected]>
*/
public class JSONParseException extends Exception {
private static final long serialVersionUID = -7880698968187728548L;
@@ -33,6 +33,7 @@ public class JSONParseException extends
public static final int ERROR_UNEXPECTED_TOKEN = 1;
public static final int ERROR_UNEXPECTED_EXCEPTION = 2;
public static final int ERROR_STRING_TOO_LONG = 3;
+ public static final int ERROR_JSON_TOO_BIG = 4;
private int errorType;
private Object unexpectedObject;
@@ -73,6 +74,9 @@ public class JSONParseException extends
case ERROR_STRING_TOO_LONG:
sb.append("String too long");
break;
+ case ERROR_JSON_TOO_BIG:
+ sb.append("JSON too big");
+ break;
default:
sb.append("Unkown error at position
").append(position).append('.');
break;
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParser.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParser.java?rev=1751876&r1=1751875&r2=1751876&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParser.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/JSONParser.java
Fri Jul 8 10:00:20 2016
@@ -26,16 +26,17 @@ import java.util.Deque;
import java.util.List;
import java.util.Map;
+import org.apache.chemistry.opencmis.commons.impl.JSONConstraints;
import org.apache.chemistry.opencmis.commons.impl.json.JSONArray;
import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
/**
* Parser for JSON text. Please note that JSONParser is NOT thread-safe.
*
- * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and modified
- * for OpenCMIS.)
+ * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and
+ * modified for OpenCMIS.)
*
- * @author FangYidong<[email protected]>
+ * @author FangYidong<[email protected]>
*/
public class JSONParser {
public static final int S_INIT = 0;
@@ -202,6 +203,9 @@ public class JSONParser {
statusStack.removeFirst();
String key = (String) valueStack.removeFirst();
Map<String, Object> parent = (Map<String, Object>)
valueStack.getFirst();
+ if (parent.size() + 1 >
JSONConstraints.MAX_OBJECT_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
parent.put(key, token.value);
status = peekStatus(statusStack);
break;
@@ -209,6 +213,12 @@ public class JSONParser {
statusStack.removeFirst();
key = (String) valueStack.removeFirst();
parent = (Map<String, Object>) valueStack.getFirst();
+ if (parent.size() + 1 >
JSONConstraints.MAX_OBJECT_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
+ if (valueStack.size() + 1 > JSONConstraints.MAX_DEPTH)
{
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
List<Object> newArray =
createArrayContainer(containerFactory);
parent.put(key, newArray);
status = S_IN_ARRAY;
@@ -219,6 +229,12 @@ public class JSONParser {
statusStack.removeFirst();
key = (String) valueStack.removeFirst();
parent = (Map<String, Object>) valueStack.getFirst();
+ if (parent.size() + 1 >
JSONConstraints.MAX_OBJECT_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
+ if (valueStack.size() + 1 > JSONConstraints.MAX_DEPTH)
{
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
Map<String, Object> newObject =
createObjectContainer(containerFactory);
parent.put(key, newObject);
status = S_IN_OBJECT;
@@ -236,6 +252,9 @@ public class JSONParser {
break;
case Yytoken.TYPE_VALUE:
List<Object> val = (List<Object>)
valueStack.getFirst();
+ if (val.size() + 1 > JSONConstraints.MAX_ARRAY_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
val.add(token.value);
break;
case Yytoken.TYPE_RIGHT_SQUARE:
@@ -249,6 +268,12 @@ public class JSONParser {
break;
case Yytoken.TYPE_LEFT_BRACE:
val = (List<Object>) valueStack.getFirst();
+ if (val.size() + 1 > JSONConstraints.MAX_ARRAY_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
+ if (valueStack.size() + 1 > JSONConstraints.MAX_DEPTH)
{
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
Map<String, Object> newObject =
createObjectContainer(containerFactory);
val.add(newObject);
status = S_IN_OBJECT;
@@ -257,6 +282,12 @@ public class JSONParser {
break;
case Yytoken.TYPE_LEFT_SQUARE:
val = (List<Object>) valueStack.getFirst();
+ if (val.size() + 1 > JSONConstraints.MAX_ARRAY_SIZE) {
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
+ if (valueStack.size() + 1 > JSONConstraints.MAX_DEPTH)
{
+ throw new
JSONParseException(JSONParseException.ERROR_JSON_TOO_BIG);
+ }
List<Object> newArray =
createArrayContainer(containerFactory);
val.add(newArray);
status = S_IN_ARRAY;
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/Yylex.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/Yylex.java?rev=1751876&r1=1751875&r2=1751876&view=diff
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/Yylex.java
(original)
+++
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/json/parser/Yylex.java
Fri Jul 8 10:00:20 2016
@@ -22,8 +22,8 @@ import java.math.BigDecimal;
import java.math.BigInteger;
/**
- * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and modified
- * for OpenCMIS.)
+ * (Taken from JSON.simple <http://code.google.com/p/json-simple/> and
+ * modified for OpenCMIS.)
*/
class Yylex {
Added:
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/json/JSONConstraintsTest.java
URL:
http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/json/JSONConstraintsTest.java?rev=1751876&view=auto
==============================================================================
---
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/json/JSONConstraintsTest.java
(added)
+++
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/test/java/org/apache/chemistry/opencmis/commons/impl/json/JSONConstraintsTest.java
Fri Jul 8 10:00:20 2016
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.chemistry.opencmis.commons.impl.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.chemistry.opencmis.commons.impl.JSONConstraints;
+import
org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParseException;
+import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParser;
+import org.junit.Test;
+
+public class JSONConstraintsTest {
+
+ private enum JSONElement {
+ VALUE, OBJECT, ARRAY
+ };
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void testObjectSize() {
+ JSONParser parser = new JSONParser();
+
+ for (JSONElement jsonElement : JSONElement.values()) {
+ JSONObject jsonObject1 =
createObject(JSONConstraints.MAX_OBJECT_SIZE, jsonElement);
+ try {
+ Object parsedObject = parser.parse(jsonObject1.toJSONString());
+ assertNotNull(parsedObject);
+ assertTrue(parsedObject instanceof Map);
+ assertEquals(JSONConstraints.MAX_OBJECT_SIZE, ((Map)
parsedObject).size());
+ } catch (JSONParseException e) {
+ fail();
+ }
+
+ JSONObject jsonObject2 =
createObject(JSONConstraints.MAX_OBJECT_SIZE + 1, jsonElement);
+ try {
+ parser.parse(jsonObject2.toJSONString());
+ fail();
+ } catch (JSONParseException e) {
+ assertEquals(JSONParseException.ERROR_JSON_TOO_BIG,
e.getErrorType());
+ }
+ }
+ }
+
+ private JSONObject createObject(int size, JSONElement jsonElement) {
+ JSONObject result = new JSONObject();
+
+ for (int i = 0; i < size; i++) {
+ switch (jsonElement) {
+ case VALUE:
+ result.put("key" + i, "value" + i);
+ break;
+ case OBJECT:
+ result.put("key" + i, new JSONObject());
+ break;
+ case ARRAY:
+ result.put("key" + i, new JSONArray());
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void testArraySize() {
+ JSONParser parser = new JSONParser();
+
+ for (JSONElement jsonElement : JSONElement.values()) {
+ JSONArray jsonArray1 = createArray(JSONConstraints.MAX_ARRAY_SIZE,
jsonElement);
+ try {
+ Object parsedObject = parser.parse(jsonArray1.toJSONString());
+ assertNotNull(parsedObject);
+ assertTrue(parsedObject instanceof List);
+ assertEquals(JSONConstraints.MAX_ARRAY_SIZE, ((List)
parsedObject).size());
+ } catch (JSONParseException e) {
+ fail();
+ }
+
+ JSONArray jsonArray2 = createArray(JSONConstraints.MAX_ARRAY_SIZE
+ 1, jsonElement);
+ try {
+ parser.parse(jsonArray2.toJSONString());
+ fail();
+ } catch (JSONParseException e) {
+ assertEquals(JSONParseException.ERROR_JSON_TOO_BIG,
e.getErrorType());
+ }
+ }
+ }
+
+ private JSONArray createArray(int size, JSONElement jsonElement) {
+ JSONArray result = new JSONArray();
+
+ for (int i = 0; i < size; i++) {
+ switch (jsonElement) {
+ case VALUE:
+ result.add("value" + i);
+ break;
+ case OBJECT:
+ result.add(new JSONObject());
+ break;
+ case ARRAY:
+ result.add(new JSONArray());
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ @Test
+ public void testDepth() {
+ JSONParser parser = new JSONParser();
+
+ JSONObject jsonObject1 = createDeepObject(JSONConstraints.MAX_DEPTH);
+ try {
+ parser.parse(jsonObject1.toJSONString());
+ } catch (JSONParseException e) {
+ fail();
+ }
+
+ JSONObject jsonObject2 = createDeepObject(JSONConstraints.MAX_DEPTH +
1);
+ try {
+ parser.parse(jsonObject2.toJSONString());
+ fail();
+ } catch (JSONParseException e) {
+ assertEquals(JSONParseException.ERROR_JSON_TOO_BIG,
e.getErrorType());
+ }
+ }
+
+ private JSONObject createDeepObject(int depth) {
+ JSONObject result = new JSONObject();
+
+ JSONObject lastObject = result;
+ for (int i = 1; i < depth; i++) {
+ JSONObject newObject = new JSONObject();
+ lastObject.put("obj", newObject);
+ lastObject = newObject;
+ }
+
+ return result;
+ }
+}