This is an automated email from the ASF dual-hosted git repository.
alopresto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/master by this push:
new 815e4cf NIFI-7152 Added custom ExceptionMappers to handle invalid
Remote Process Group port value - (#4085)
815e4cf is described below
commit 815e4cf51f913645352899837f702c7cd4f3a246
Author: Andy LoPresto <[email protected]>
AuthorDate: Tue Feb 25 13:14:52 2020 -0800
NIFI-7152 Added custom ExceptionMappers to handle invalid Remote Process
Group port value - (#4085)
JsonContentConversionExceptionMapper, JsonMappingExceptionMapper,
JsonParseExceptionMapper.
Registered the custom ExceptionMappers.
Added unit tests to throw Exception for string port value and sanitize
script input. Handled null or empty JsonMappingException reference path.
Added the Apache license to Groovy Test.
Signed-off-by: Andy LoPresto <[email protected]>
---
.../apache/nifi/web/NiFiWebApiResourceConfig.java | 6 +-
.../JsonContentConversionExceptionMapper.java | 67 +++++++++++++
.../web/api/config/JsonMappingExceptionMapper.java | 47 ++++++++++
.../web/api/config/JsonParseExceptionMapper.java | 46 +++++++++
...JsonContentConversionExceptionMapperTest.groovy | 104 +++++++++++++++++++++
5 files changed, 268 insertions(+), 2 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiResourceConfig.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiResourceConfig.java
index 4f19596..7569b37 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiResourceConfig.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiResourceConfig.java
@@ -30,6 +30,9 @@ import
org.apache.nifi.web.api.config.IllegalNodeReconnectionExceptionMapper;
import org.apache.nifi.web.api.config.IllegalStateExceptionMapper;
import org.apache.nifi.web.api.config.InvalidAuthenticationExceptionMapper;
import org.apache.nifi.web.api.config.InvalidRevisionExceptionMapper;
+import org.apache.nifi.web.api.config.JsonMappingExceptionMapper;
+import org.apache.nifi.web.api.config.JsonParseExceptionMapper;
+import org.apache.nifi.web.api.config.JsonContentConversionExceptionMapper;
import org.apache.nifi.web.api.config.MutableRequestExceptionMapper;
import org.apache.nifi.web.api.config.NiFiCoreExceptionMapper;
import org.apache.nifi.web.api.config.NoClusterCoordinatorExceptionMapper;
@@ -46,8 +49,6 @@ import
org.apache.nifi.web.api.config.WebApplicationExceptionMapper;
import org.apache.nifi.web.api.filter.RedirectResourceFilter;
import org.apache.nifi.web.util.ObjectMapperResolver;
import org.glassfish.jersey.jackson.JacksonFeature;
-import
org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.JsonMappingExceptionMapper;
-import
org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.JsonParseExceptionMapper;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.message.GZipEncoder;
import org.glassfish.jersey.server.ResourceConfig;
@@ -118,6 +119,7 @@ public class NiFiWebApiResourceConfig extends
ResourceConfig {
register(InvalidRevisionExceptionMapper.class);
register(JsonMappingExceptionMapper.class);
register(JsonParseExceptionMapper.class);
+ register(JsonContentConversionExceptionMapper.class);
register(MutableRequestExceptionMapper.class);
register(NiFiCoreExceptionMapper.class);
register(NoConnectedNodesExceptionMapper.class);
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapper.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapper.java
new file mode 100644
index 0000000..51109ca
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.nifi.web.api.config;
+
+ import com.fasterxml.jackson.databind.JsonMappingException;
+ import com.fasterxml.jackson.databind.exc.InvalidFormatException;
+ import org.apache.nifi.util.EscapeUtils;
+ import org.apache.nifi.util.StringUtils;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import javax.ws.rs.core.Response;
+ import javax.ws.rs.ext.ExceptionMapper;
+ import javax.ws.rs.ext.Provider;
+
+/**
+ * Maps invalid revision exceptions into client responses.
+ */
+@Provider
+public class JsonContentConversionExceptionMapper implements
ExceptionMapper<InvalidFormatException> {
+
+ private static final Logger logger =
LoggerFactory.getLogger(JsonContentConversionExceptionMapper.class);
+
+ @Override
+ public Response toResponse(InvalidFormatException ex) {
+ // log the error
+ logger.info(String.format("%s. Returning %s response.", ex,
Response.Status.BAD_REQUEST));
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(StringUtils.EMPTY, ex);
+ }
+
+ String value = ex.getValue().toString();
+ String propName = "field";
+
+ if (ex.getPath() != null && !ex.getPath().isEmpty()) {
+ JsonMappingException.Reference path =
ex.getPath().get(ex.getPath().size() - 1);
+ if (path != null) {
+ propName = path.getFieldName();
+ }
+ }
+
+ String errorMessage = "The provided " + propName + " value '" +
sanitizeMessage(value) + "' is not of required type " + ex.getTargetType();
+
+ logger.error(errorMessage);
+
+ return
Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).type("text/plain").build();
+ }
+
+ private static String sanitizeMessage(String input) {
+ return EscapeUtils.escapeHtml(input);
+ }
+}
\ No newline at end of file
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonMappingExceptionMapper.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonMappingExceptionMapper.java
new file mode 100644
index 0000000..f03c08e
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonMappingExceptionMapper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.nifi.web.api.config;
+
+import com.fasterxml.jackson.databind.JsonMappingException;
+import org.apache.nifi.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Maps invalid revision exceptions into client responses.
+ */
+@Provider
+public class JsonMappingExceptionMapper implements
ExceptionMapper<JsonMappingException> {
+
+ private static final Logger logger =
LoggerFactory.getLogger(JsonMappingExceptionMapper.class);
+
+ @Override
+ public Response toResponse(JsonMappingException ex) {
+ // log the error
+ logger.info(String.format("%s. Returning %s response.", ex,
Response.Status.BAD_REQUEST));
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(StringUtils.EMPTY, ex);
+ }
+
+ return Response.status(Response.Status.BAD_REQUEST).entity("Message
body is malformed. Unable to map into expected
format.").type("text/plain").build();
+ }
+}
\ No newline at end of file
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonParseExceptionMapper.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonParseExceptionMapper.java
new file mode 100644
index 0000000..3d6d49b
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/JsonParseExceptionMapper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.nifi.web.api.config;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import org.apache.nifi.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.fasterxml.jackson.core.JsonParseException;
+
+/**
+ * Maps invalid revision exceptions into client responses.
+ */
+@Provider
+public class JsonParseExceptionMapper implements
ExceptionMapper<JsonParseException> {
+
+ private static final Logger logger =
LoggerFactory.getLogger(JsonMappingExceptionMapper.class);
+
+ @Override
+ public Response toResponse(JsonParseException ex) {
+ // log the error
+ logger.info(String.format("%s. Returning %s response.", ex,
Response.Status.BAD_REQUEST));
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(StringUtils.EMPTY, ex);
+ }
+
+ return Response.status(Response.Status.BAD_REQUEST).entity("Unable to
parse body as JSON.").type("text/plain").build();
+ }
+}
\ No newline at end of file
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapperTest.groovy
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapperTest.groovy
new file mode 100644
index 0000000..4b1ebef
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/api/config/JsonContentConversionExceptionMapperTest.groovy
@@ -0,0 +1,104 @@
+/*
+ * 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.nifi.web.api.config
+
+import com.fasterxml.jackson.core.JsonLocation
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.JsonMappingException
+import com.fasterxml.jackson.databind.exc.InvalidFormatException
+import org.apache.nifi.web.api.ProcessGroupResourceTest
+import org.junit.Rule
+import org.junit.rules.TestName
+import org.junit.BeforeClass
+import org.junit.Before
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import javax.ws.rs.core.Response
+
+@RunWith(JUnit4.class)
+class JsonContentConversionExceptionMapperTest extends GroovyTestCase {
+ private static final Logger logger =
LoggerFactory.getLogger(ProcessGroupResourceTest.class)
+
+ @Rule
+ public TestName testName = new TestName()
+
+ @BeforeClass
+ static void setUpOnce() throws Exception {
+ logger.metaClass.methodMissing = { String name, args ->
+ logger.debug("[${name?.toUpperCase()}] ${(args as List).join("
")}")
+ }
+ }
+
+ @Before
+ void setUp() throws Exception {
+ }
+
+ @After
+ void tearDown() throws Exception {
+ }
+
+ @Test
+ void testShouldThrowExceptionWithStringPortValue() throws Exception{
+ // Arrange
+ JsonContentConversionExceptionMapper jsonCCEM = new
JsonContentConversionExceptionMapper()
+
+ // Using real exception
+ Class<?> instClass = Integer.class
+ def mockParser = [getTokenLocation: { -> return new JsonLocation(null,
100, 1, 1)}] as JsonParser
+ String message = "Some message"
+ String value = "thisIsAnInvalidPort"
+ InvalidFormatException ife = InvalidFormatException.from(mockParser,
message, value, instClass)
+ JsonMappingException.wrapWithPath(ife, new
JsonMappingException.Reference("RemoteProcessGroupDTO", "proxyPort"))
+ JsonMappingException.wrapWithPath(ife, new
JsonMappingException.Reference("RemoteProcessGroupEntity", "component"))
+
+ // Act
+ Response response = jsonCCEM.toResponse(ife)
+ logger.info(response.toString())
+
+ // Assert
+ assert response.status == Response.Status.BAD_REQUEST.statusCode
+ assert response.entity == "The provided proxyPort value
\'thisIsAnInvalidPort\' is not of required type class java.lang.Integer"
+ }
+
+ @Test
+ void testShouldSanitizeScriptInInput() throws Exception{
+ // Arrange
+ JsonContentConversionExceptionMapper jsonCCEM = new
JsonContentConversionExceptionMapper();
+
+ // Using real exception
+ Class<?> instClass = Integer.class
+ def mockParser = [getTokenLocation: { -> return new JsonLocation(null,
100, 1, 1)}] as JsonParser
+ String message = "Some message"
+ String value = "<script>alert(1);</script>"
+ InvalidFormatException ife = InvalidFormatException.from(mockParser,
message, value, instClass)
+ JsonMappingException.wrapWithPath(ife, new
JsonMappingException.Reference("RemoteProcessGroupDTO", "proxyPort"))
+ JsonMappingException.wrapWithPath(ife, new
JsonMappingException.Reference("RemoteProcessGroupEntity", "component"))
+
+ // Act
+ Response response = jsonCCEM.toResponse(ife)
+ logger.info(response.toString())
+
+ // Assert
+ assert response.status == Response.Status.BAD_REQUEST.statusCode
+ assert !(response.entity =~ /<script.*>/)
+ }
+}