Skip to content

Commit

Permalink
[RESTEASY-1485] added classes and adjusted test cases. Created util, …
Browse files Browse the repository at this point in the history
…escapeXml. This closes #957
  • Loading branch information
rsearls authored and asoldano committed Sep 29, 2016
1 parent 0d9ce4e commit 0f59bdf
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.jboss.resteasy.plugins.providers.jackson;

import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.util.HttpResponseCodes;

/**
* (RESTEASY-1485) Address concerns of a possible XSS attack by removing some
* details of the exception.
*
* User: rsearls
* Date: 9/22/16
*/
@Provider
public class UnrecognizedPropertyExceptionHandler implements ExceptionMapper<UnrecognizedPropertyException> {
@Override
public Response toResponse(UnrecognizedPropertyException exception)
{
return Response.status(HttpResponseCodes.SC_BAD_REQUEST)
.type(MediaType.TEXT_HTML)
.entity(exception.getOriginalMessage())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider
org.jboss.resteasy.plugins.providers.jackson.UnrecognizedPropertyExceptionHandler
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.jboss.resteasy.plugins.interceptors.encoding;

import java.io.IOException;
import java.util.HashMap;
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.util.HttpResponseCodes;

/**
* (RESTEASY-1485) Thwart select XSS attack by escaping special chars in
* Exception message.
*
* User: rsearls
* Date: 9/16/16
*/
@Provider
@Priority(Priorities.ENTITY_CODER)
public class MessageSanitizerContainerResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {

if (HttpResponseCodes.SC_BAD_REQUEST == responseContext.getStatus()) {
Object entity = responseContext.getEntity();
if (entity != null && entity instanceof String) {
String escapedMsg = escapeXml((String) entity);
responseContext.setEntity(escapedMsg);
}
}
}


// set of replacement chars to hex encoding
private static final HashMap<String, String> replacementMap;
static {
replacementMap = new HashMap<String, String>();
replacementMap.put("/", "&#x2F;");
replacementMap.put("<", "&lt;");
replacementMap.put(">", "&gt;");
replacementMap.put("&", "&amp;");
replacementMap.put("\"", "&quot;");
replacementMap.put("'", "&#x27;");
}

/**
* Replace char with the hex encoding
* @param str
* @return
*/
private String escapeXml(String str) {
StringBuilder sb = new StringBuilder();
if (!str.isEmpty()) {
// the vertical bar, |, is a special regular expression char that
// causes splitting on individual characters.
for (String key : str.split("|")) {
String value = replacementMap.get(key);
if (value == null) {
sb.append(key);
} else {
sb.append(value);
}

}
}
return sb.toString();
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ org.jboss.resteasy.plugins.providers.IIOImageProvider
org.jboss.resteasy.plugins.interceptors.CacheControlFeature
org.jboss.resteasy.plugins.interceptors.encoding.ClientContentEncodingAnnotationFeature
org.jboss.resteasy.plugins.interceptors.encoding.ServerContentEncodingAnnotationFeature
org.jboss.resteasy.plugins.interceptors.encoding.MessageSanitizerContainerResponseFilter


Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void testViolationsBeforeReturnValue() throws Exception {
Assert.assertEquals(WRONG_ERROR_MSG, "size must be between 3 and 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "z", violation.getValue());
violation = e.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", violation.getMessage());
Assert.assertTrue(WRONG_ERROR_MSG, violation.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ValidationCoreResourceWithAllViolationTypes@"));
response.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ public void testViolationsBeforeReturnValue() throws Exception {
Assert.assertEquals("Exception has wrong message", "size must be between 3 and 5", cv.getMessage());
Assert.assertEquals("Exception has wrong value", "z", cv.getValue());
cv = e.getClassViolations().iterator().next();
Assert.assertEquals("Exception has wrong message", "Concatenation of s and t must have length > 5", cv.getMessage());
Assert.assertEquals("Exception has wrong message", "Concatenation of s and t must have length &gt; 5", cv.getMessage());
logger.info("value: " + cv.getValue());
Assert.assertTrue("Exception has wrong value", cv.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ViolationExceptionResourceWithFiveViolations@"));
cv = e.getParameterViolations().iterator().next();
Assert.assertEquals("Exception has wrong message", "s must have length: 3 <= length <= 5", cv.getMessage());
Assert.assertEquals("Exception has wrong message", "s must have length: 3 &lt;= length &lt;= 5", cv.getMessage());
Assert.assertEquals("Exception has wrong value", "Foo[p]", cv.getValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,8 @@ public void testClassConstraint() throws Exception {
ViolationReport r = new ViolationReport(entity);
TestUtil.countViolations(r, 0, 0, 1, 0, 0);
ResteasyConstraintViolation cv = r.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "ValidationComplexResourceWithClassConstraint(\"a\", \"b\")", cv.getValue());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "ValidationComplexResourceWithClassConstraint(&quot;a&quot;, &quot;b&quot;)", cv.getValue());
logger.info(cv.getValue());
response.close();
}
Expand Down Expand Up @@ -542,7 +542,7 @@ public void testParameters() throws Exception {
ViolationReport r = new ViolationReport(entity);
TestUtil.countViolations(r, 0, 0, 0, 1, 0);
ResteasyConstraintViolation cv = r.getParameterViolations().iterator().next();
Assert.assertTrue(WRONG_ERROR_MSG, cv.getMessage().equals("s must have length: 1 <= length <= 3"));
Assert.assertTrue(WRONG_ERROR_MSG, cv.getMessage().equals("s must have length: 1 &lt;= length &lt;= 3"));
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[abcdef]", cv.getValue());
response.close();

Expand All @@ -554,7 +554,7 @@ public void testParameters() throws Exception {
r = new ViolationReport(String.class.cast(entity));
TestUtil.countViolations(r, 0, 0, 0, 1, 0);
cv = r.getParameterViolations().iterator().next();
Assert.assertTrue(WRONG_ERROR_MSG, cv.getMessage().equals("s must have length: 3 <= length <= 5"));
Assert.assertTrue(WRONG_ERROR_MSG, cv.getMessage().equals("s must have length: 3 &lt;= length &lt;= 5"));
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[abcdef]", cv.getValue());
response.close();

Expand All @@ -573,9 +573,9 @@ public void testParameters() throws Exception {
cv1 = cv2;
cv2 = temp;
}
Assert.assertTrue(WRONG_ERROR_MSG, cv1.getMessage().equals("s must have length: 1 <= length <= 3"));
Assert.assertTrue(WRONG_ERROR_MSG, cv1.getMessage().equals("s must have length: 1 &lt;= length &lt;= 3"));
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[abcdef]", cv1.getValue());
Assert.assertTrue(WRONG_ERROR_MSG, cv2.getMessage().equals("s must have length: 3 <= length <= 5"));
Assert.assertTrue(WRONG_ERROR_MSG, cv2.getMessage().equals("s must have length: 3 &lt;= length &lt;= 5"));
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[abcdef]", cv2.getValue());
response.close();

Expand Down Expand Up @@ -714,10 +714,10 @@ public void testViolationsBeforeReturnValue() throws Exception {
Assert.assertEquals(WRONG_ERROR_MSG, "size must be between 3 and 5", cv.getMessage());
Assert.assertEquals(RESPONSE_ERROR_MSG, "z", cv.getValue());
cv = r.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", cv.getMessage());
Assert.assertTrue(WRONG_ERROR_MSG, cv.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ValidationComplexResourceWithAllFivePotentialViolations@"));
cv = r.getParameterViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 <= length <= 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 &lt;= length &lt;= 5", cv.getMessage());
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[p]", cv.getValue());
response.close();
}
Expand Down Expand Up @@ -876,7 +876,7 @@ public void testLocators() throws Exception {
cv = r.getPropertyViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "size must be between 3 and 5", cv.getMessage());
cv = r.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", cv.getMessage());
Assert.assertTrue(RESPONSE_ERROR_MSG, cv.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ValidationComplexResourceWithAllFivePotentialViolations@"));
response.close();

Expand Down Expand Up @@ -936,10 +936,10 @@ public void testAsynch() throws Exception {
Assert.assertEquals(WRONG_ERROR_MSG, "size must be between 3 and 5", cv.getMessage());
Assert.assertEquals(RESPONSE_ERROR_MSG, "z", cv.getValue());
cv = r.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", cv.getMessage());
Assert.assertTrue(RESPONSE_ERROR_MSG, cv.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ValidationComplexResourceWithAllFivePotentialViolations@"));
cv = r.getParameterViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 <= length <= 5", cv.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 &lt;= length &lt;= 5", cv.getMessage());
Assert.assertEquals(RESPONSE_ERROR_MSG, "ValidationComplexFoo[p]", cv.getValue());
response.close();

Expand Down Expand Up @@ -1008,7 +1008,7 @@ public void testCrossParameterConstraint() throws Exception {
TestUtil.countViolations(r, 0, 0, 0, 1, 0);
ResteasyConstraintViolation violation = r.getParameterViolations().iterator().next();
logger.info("violation: " + violation);
Assert.assertEquals(WRONG_ERROR_MSG, "Parameters must total <= 7", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Parameters must total &lt;= 7", violation.getMessage());
logger.info("violation value: " + violation.getValue());
Assert.assertEquals(RESPONSE_ERROR_MSG, "[5, 7]", violation.getValue());
response.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ public void testViolationsBeforeReturnValue() throws Exception {
Assert.assertEquals(WRONG_ERROR_MSG, "size must be between 3 and 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "z", violation.getValue());
violation = r.getClassViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length > 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "Concatenation of s and t must have length &gt; 5", violation.getMessage());
Assert.assertTrue(WRONG_ERROR_MSG, violation.getValue().startsWith("org.jboss.resteasy.test.validation.resource.ValidationCoreResourceWithAllViolationTypes@"));
violation = r.getParameterViolations().iterator().next();
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 <= length <= 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "s must have length: 3 &lt;= length &lt;= 5", violation.getMessage());
Assert.assertEquals(WRONG_ERROR_MSG, "ValidationCoreFoo[p]", violation.getValue());
response.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,12 +371,12 @@ protected void doTestText_pre(String mediaType) throws Exception {
String classViolation =
"[CLASS]\r" +
"[]\r" +
"[Concatenation of s and u must have length > 5]\r" +
"[Concatenation of s and u must have length &gt; 5]\r" +
"[org.jboss.resteasy.test.validation.resource.ValidationXMLResourceWithAllFivePotentialViolations";
String parameterViolation =
"[PARAMETER]\r" +
"[post.arg0]\r" +
"[s must have length: 3 <= length <= 5]\r" +
"[s must have length: 3 &lt;= length &lt;= 5]\r" +
"[ValidationXMLFoo[p]]";
Assert.assertTrue(WRONG_ERROR_MSG, entity.contains(fieldViolation1));
Assert.assertTrue(WRONG_ERROR_MSG, entity.contains(fieldViolation2));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ void doDTDFails(String ext) throws Exception {
Assert.assertEquals(HttpResponseCodes.SC_BAD_REQUEST, response.getStatus());
Assert.assertThat("Wrong exception in response", entity, startsWith("javax.xml.bind.UnmarshalException"));
Assert.assertThat("Wrong content of response", entity, containsString("DOCTYPE"));
Assert.assertThat("Wrong content of response", entity, containsString("http://apache.org/xml/features/disallow-doctype-decl"));
Assert.assertThat("Wrong content of response", entity, containsString("http:&#x2F;&#x2F;apache.org&#x2F;xml&#x2F;features&#x2F;disallow-doctype-decl"));
Assert.assertThat("Wrong content of response", entity, containsString("true"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ void doDTDFails(String ext) throws Exception {
Assert.assertEquals(HttpResponseCodes.SC_BAD_REQUEST, response.getStatus());
Assert.assertThat("Wrong exception in response", entity, startsWith("javax.xml.bind.UnmarshalException"));
Assert.assertThat("Wrong content of response", entity, containsString("DOCTYPE"));
Assert.assertThat("Wrong content of response", entity, containsString("http://apache.org/xml/features/disallow-doctype-decl"));
Assert.assertThat("Wrong content of response", entity, containsString("http:&#x2F;&#x2F;apache.org&#x2F;xml&#x2F;features&#x2F;disallow-doctype-decl"));
Assert.assertThat("Wrong content of response", entity, containsString("true"));
}

Expand Down

0 comments on commit 0f59bdf

Please sign in to comment.