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.*>/)
+    }
+}

Reply via email to