Ravi Nori has uploaded a new change for review.

Change subject: restapi : ints and shorts overflow
......................................................................

restapi : ints and shorts overflow

int and short values are overflown before
they even reach the business code, allowing
for wrong values to be set.

When posting to rest api, if the value of an
int is greater than Integer.MAX_VALUE or value
of a short is larger than Short.MAX_VALUE. The
values are overflown when values are unmarshalled
using JAXB.

An excpetion should be raised during JAXB
unmarshalling to indicate that the value is
greater than the MAX_VALUE for the type.

Change-Id: I9d0be6f3f220d7a5f58bb47906a8565d80e0ebf0
Bug-Url: https://bugzilla.redhat.com/1000796
Signed-off-by: Ravi Nori <rn...@redhat.com>
---
A 
backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/IntegerParser.java
A 
backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/InvalidValueException.java
M 
backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
M backend/manager/modules/restapi/jaxrs/pom.xml
M 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/BackendApplication.java
A 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/InvalidValueExceptionMapper.java
A 
backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/XmlMessageBodyReader.java
M 
backend/manager/modules/restapi/types/src/test/java/org/ovirt/engine/api/restapi/types/VmMapperTest.java
8 files changed, 168 insertions(+), 7 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/56/23856/1

diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/IntegerParser.java
 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/IntegerParser.java
new file mode 100644
index 0000000..67f8a20
--- /dev/null
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/IntegerParser.java
@@ -0,0 +1,29 @@
+package org.ovirt.engine.api.utils;
+
+import javax.xml.bind.DatatypeConverter;
+import java.math.BigInteger;
+
+public class IntegerParser {
+
+    public static int parseIntegerToShort(String value) {
+        BigInteger result =
+                DatatypeConverter.parseInteger(value);
+        if (result.longValue() > Short.MAX_VALUE) {
+            throw new InvalidValueException("Value " +value+ " greater than 
Short.MAX_VALUE");
+        }
+        return result.intValue();
+    }
+
+    public static int parseIntegerToInt(String value) {
+        BigInteger result =
+                DatatypeConverter.parseInteger(value);
+        if (result.longValue() > Integer.MAX_VALUE) {
+            throw new InvalidValueException("Value " +value+ " greater than 
Integer.MAX_VALUE");
+        }
+        return result.intValue();
+    }
+
+    public static String printIntToInteger(int value) {
+        return DatatypeConverter.printInteger(BigInteger.valueOf(value));
+    }
+}
diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/InvalidValueException.java
 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/InvalidValueException.java
new file mode 100644
index 0000000..295940d
--- /dev/null
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/utils/InvalidValueException.java
@@ -0,0 +1,9 @@
+package org.ovirt.engine.api.utils;
+
+public class InvalidValueException extends RuntimeException {
+
+    public InvalidValueException(String msg) {
+         super(msg);
+    }
+
+}
diff --git 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
index 46aa30f..05f821a 100644
--- 
a/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
+++ 
b/backend/manager/modules/restapi/interface/definition/src/main/resources/api.xsd
@@ -4,9 +4,19 @@
            xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc";
            jaxb:version="2.1" jaxb:extensionBindingPrefixes="xjc">
 
+
   <xs:annotation>
     <xs:appinfo>
-      <jaxb:globalBindings generateIsSetMethod="true"/>
+      <jaxb:globalBindings generateIsSetMethod="true">
+         <jaxb:javaType name="int" xmlType="xs:int"
+           
parseMethod="org.ovirt.engine.api.utils.IntegerParser.parseIntegerToInt"
+           
printMethod="org.ovirt.engine.api.utils.IntegerParser.printIntToInteger"
+         />
+         <jaxb:javaType name="int" xmlType="xs:unsignedShort"
+           
parseMethod="org.ovirt.engine.api.utils.IntegerParser.parseIntegerToShort"
+           
printMethod="org.ovirt.engine.api.utils.IntegerParser.printIntToInteger"
+         />
+       </jaxb:globalBindings>
     </xs:appinfo>
   </xs:annotation>
 
diff --git a/backend/manager/modules/restapi/jaxrs/pom.xml 
b/backend/manager/modules/restapi/jaxrs/pom.xml
index 8a29d6a..3fa9396 100644
--- a/backend/manager/modules/restapi/jaxrs/pom.xml
+++ b/backend/manager/modules/restapi/jaxrs/pom.xml
@@ -107,6 +107,11 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+      <dependency>
+          <groupId>org.jboss.resteasy</groupId>
+          <artifactId>resteasy-jaxb-provider</artifactId>
+          <version>2.3.2.Final</version>
+      </dependency>
 
   </dependencies>
 
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/BackendApplication.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/BackendApplication.java
index fb0a3fe..ed0036c 100644
--- 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/BackendApplication.java
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/BackendApplication.java
@@ -58,10 +58,12 @@
 import org.ovirt.engine.api.restapi.resource.BackendVmPoolsResource;
 import org.ovirt.engine.api.restapi.resource.BackendVmsResource;
 import org.ovirt.engine.api.restapi.resource.BackendVnicProfilesResource;
+import 
org.ovirt.engine.api.restapi.resource.validation.InvalidValueExceptionMapper;
 import org.ovirt.engine.api.restapi.resource.validation.JaxbExceptionMapper;
 import org.ovirt.engine.api.restapi.resource.validation.JsonExceptionMapper;
 import 
org.ovirt.engine.api.restapi.resource.validation.MalformedIdExceptionMapper;
 import org.ovirt.engine.api.restapi.resource.validation.ValidatorLocator;
+import org.ovirt.engine.api.restapi.resource.validation.XmlMessageBodyReader;
 import org.ovirt.engine.api.restapi.security.auth.LoginValidator;
 import org.ovirt.engine.api.restapi.types.MappingLocator;
 import org.ovirt.engine.api.restapi.util.SessionHelper;
@@ -161,11 +163,13 @@
         singletons.add(new RequestPayloadLogger());
         singletons.add(new ResponseStatusLogger());
         singletons.add(new ResponsePayloadLogger());
+        singletons.add(new XmlMessageBodyReader());
 
         // Intercepter that maps exceptions cause by illegal guid string to 
400 status (BAD_REQUEST).
         singletons.add(new MalformedIdExceptionMapper());
         singletons.add(new JaxbExceptionMapper());
         singletons.add(new JsonExceptionMapper());
+        singletons.add(new InvalidValueExceptionMapper());
     }
 
     private void addResource(final BackendResource resource) {
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/InvalidValueExceptionMapper.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/InvalidValueExceptionMapper.java
new file mode 100644
index 0000000..fcc7a28
--- /dev/null
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/InvalidValueExceptionMapper.java
@@ -0,0 +1,20 @@
+package org.ovirt.engine.api.restapi.resource.validation;
+
+import org.ovirt.engine.api.model.Fault;
+import org.ovirt.engine.api.utils.InvalidValueException;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class InvalidValueExceptionMapper implements 
ExceptionMapper<InvalidValueException> {
+
+    @Override
+    public javax.ws.rs.core.Response toResponse(InvalidValueException e) {
+        Fault fault = new Fault();
+        fault.setReason("Invalid Value");
+        fault.setDetail(e.getMessage());
+        return 
Response.status(Response.Status.BAD_REQUEST).entity(fault).build();
+    }
+}
diff --git 
a/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/XmlMessageBodyReader.java
 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/XmlMessageBodyReader.java
new file mode 100644
index 0000000..7645db3
--- /dev/null
+++ 
b/backend/manager/modules/restapi/jaxrs/src/main/java/org/ovirt/engine/api/restapi/resource/validation/XmlMessageBodyReader.java
@@ -0,0 +1,84 @@
+package org.ovirt.engine.api.restapi.resource.validation;
+
+import org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider;
+import org.jboss.resteasy.plugins.providers.jaxb.JAXBContextFinder;
+import org.jboss.resteasy.plugins.providers.jaxb.JAXBMarshalException;
+import org.ovirt.engine.api.utils.InvalidValueException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.ws.rs.ext.Providers;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.helpers.DefaultValidationEventHandler;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+@Provider
+@Consumes({ MediaType.APPLICATION_XML })
+public class XmlMessageBodyReader implements MessageBodyReader<Object> {
+
+    /** XML parsers */
+    @Context
+    protected Providers providers;
+
+    /** Default event handler recognizes XML parsing as error and not as 
warning */
+    private ValidationEventHandler errorhandler = new 
DefaultValidationEventHandler();
+
+    protected JAXBContextFinder getFinder(MediaType type) {
+        ContextResolver<JAXBContextFinder> resolver = 
providers.getContextResolver(JAXBContextFinder.class, type);
+        if (resolver == null) {
+            throw new IllegalArgumentException("Unable to find ContextResolver 
for media type: " + type);
+        }
+        return resolver.getContext(null);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] 
annotations, MediaType mediaType) {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Standard JAXB unmarshaller with custom error handler- {@link 
#errorhandler}
+     */
+    @Override
+    public Object readFrom(Class<Object> type, Type genericType, Annotation[] 
annotations, MediaType mediaType,
+                           MultivaluedMap<String, String> httpHeaders, 
InputStream entityStream) throws IOException, WebApplicationException {
+
+        if (entityStream == null) {
+            return null;
+        }
+        try {
+            JAXBContext ctx = getFinder(mediaType).findCacheContext(mediaType, 
annotations, type);
+            Unmarshaller unmarshaller = ctx.createUnmarshaller();
+
+            AbstractJAXBProvider.decorateUnmarshaller(type, annotations, 
mediaType, unmarshaller);
+
+            unmarshaller.setEventHandler(errorhandler);
+            Object parsedObj = unmarshaller.unmarshal(entityStream);
+            if (parsedObj instanceof JAXBElement) {
+                return ((JAXBElement) parsedObj).getValue();
+            }
+            return parsedObj;
+        } catch (JAXBException e) {
+            if (e.getLinkedException().getCause() instanceof 
InvalidValueException) {
+                throw (InvalidValueException) 
e.getLinkedException().getCause();
+            }
+            throw new JAXBMarshalException(e);
+        }
+    }
+}
diff --git 
a/backend/manager/modules/restapi/types/src/test/java/org/ovirt/engine/api/restapi/types/VmMapperTest.java
 
b/backend/manager/modules/restapi/types/src/test/java/org/ovirt/engine/api/restapi/types/VmMapperTest.java
index 8bff7af..229e994 100644
--- 
a/backend/manager/modules/restapi/types/src/test/java/org/ovirt/engine/api/restapi/types/VmMapperTest.java
+++ 
b/backend/manager/modules/restapi/types/src/test/java/org/ovirt/engine/api/restapi/types/VmMapperTest.java
@@ -258,7 +258,7 @@
         assertNotNull(cpuTune);
         assertNotNull(cpuTune.getVCpuPin());
         assertEquals(1, cpuTune.getVCpuPin().size());
-        assertEquals(0, cpuTune.getVCpuPin().get(0).getVcpu());
+        assertEquals(0, (int) cpuTune.getVCpuPin().get(0).getVcpu());
         assertEquals("0", cpuTune.getVCpuPin().get(0).getCpuSet());
     }
 
@@ -275,26 +275,26 @@
     @Test()
     public void stringToVCpupinIntervalsList() {
         VCpuPin pin = VmMapper.stringToVCpupin("1#1-4,6");
-        assertEquals(1, pin.getVcpu());
+        assertEquals(1, (int) pin.getVcpu());
         assertEquals("1-4,6", pin.getCpuSet());
     }
 
     @Test()
     public void stringToVCpupinSimple() {
         VCpuPin pin = VmMapper.stringToVCpupin("1#1");
-        assertEquals(1, pin.getVcpu());
+        assertEquals(1, (int) pin.getVcpu());
         assertEquals("1", pin.getCpuSet());
 
         pin = VmMapper.stringToVCpupin("1#10");
-        assertEquals(1, pin.getVcpu());
+        assertEquals(1, (int) pin.getVcpu());
         assertEquals("10", pin.getCpuSet());
 
         pin = VmMapper.stringToVCpupin("1#10,11,12");
-        assertEquals(1, pin.getVcpu());
+        assertEquals(1, (int) pin.getVcpu());
         assertEquals("10,11,12", pin.getCpuSet());
 
         pin = VmMapper.stringToVCpupin("1#10-12,16");
-        assertEquals(1, pin.getVcpu());
+        assertEquals(1, (int) pin.getVcpu());
         assertEquals("10-12,16", pin.getCpuSet());
     }
 


-- 
To view, visit http://gerrit.ovirt.org/23856
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I9d0be6f3f220d7a5f58bb47906a8565d80e0ebf0
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Ravi Nori <rn...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to