NIFI-494:

- Escaping parameters as appropriate.
- Additional error handling.
This commit is contained in:
Matt Gilman 2015-04-09 15:49:46 -04:00
parent 2154b822bf
commit eb023e57b2
16 changed files with 165 additions and 30 deletions

View File

@ -0,0 +1,42 @@
/*
* 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.util;
public class EscapeUtils {
/**
* Escapes the specified html by replacing &, <, >, ", ', /
* with their corresponding html entity. If html is null, null is returned.
*
* @param html
* @return
*/
public static String escapeHtml(String html) {
if (html == null) {
return null;
}
html = html.replace("&", "&");
html = html.replace("<", "&lt;");
html = html.replace(">", "&gt;");
html = html.replace("\"", "&quot;");
html = html.replace("'", "&#39;");
html = html.replace("/", "&#x2f;");
return html;
}
}

View File

@ -121,8 +121,14 @@ public class StandardNiFiContentAccess implements ContentAccess {
final String rawDirection = StringUtils.substringAfterLast(eventDetails, "/content/");
// get the content type
final Long eventId = Long.parseLong(rawEventId);
final ContentDirection direction = ContentDirection.valueOf(rawDirection.toUpperCase());
final Long eventId;
final ContentDirection direction;
try {
eventId = Long.parseLong(rawEventId);
direction = ContentDirection.valueOf(rawDirection.toUpperCase());
} catch (final IllegalArgumentException iae) {
throw new IllegalArgumentException("The specified data reference URI is not valid.");
}
return serviceFacade.getContent(eventId, request.getDataUri(), direction);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.sun.jersey.api.NotFoundException;
import com.sun.jersey.api.Responses;
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;
/**
* Maps not found exceptions into client responses.
*/
@Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
private static final Logger logger = LoggerFactory.getLogger(NotFoundExceptionMapper.class);
@Override
public Response toResponse(NotFoundException exception) {
// log the error
logger.info(String.format("%s. Returning %s response.", exception, Response.Status.NOT_FOUND));
if (logger.isDebugEnabled()) {
logger.debug(StringUtils.EMPTY, exception);
}
return Responses.notFound().entity("The specified resource could not be found.").type("text/plain").build();
}
}

View File

@ -270,6 +270,7 @@
<bean class="org.apache.nifi.web.api.config.NodeReconnectionExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.PrimaryRoleAssignmentExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.ResourceNotFoundExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.NotFoundExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.UnknownNodeExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.ValidationExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.WebApplicationExceptionMapper" scope="singleton"/>

View File

@ -68,10 +68,21 @@ public class ContentViewerController extends HttpServlet {
final ServletContext servletContext = request.getServletContext();
final ContentAccess contentAccess = (ContentAccess) servletContext.getAttribute("nifi-content-access");
final ContentRequestContext contentRequest = getContentRequest(request);
if (contentRequest.getDataUri() == null) {
request.setAttribute("title", "Error");
request.setAttribute("messages", "The data reference must be specified.");
// forward to the error page
final ServletContext viewerContext = servletContext.getContext("/nifi");
viewerContext.getRequestDispatcher("/message").forward(request, response);
return;
}
// get the content
final DownloadableContent downloadableContent;
try {
downloadableContent = contentAccess.getContent(getContentRequest(request));
downloadableContent = contentAccess.getContent(contentRequest);
} catch (final ResourceNotFoundException rnfe) {
request.setAttribute("title", "Error");
request.setAttribute("messages", "Unable to find the specified content");
@ -138,9 +149,6 @@ public class ContentViewerController extends HttpServlet {
final String mimeType = mediatype.toString();
// add attributes needed for the header
final StringBuffer requestUrl = request.getRequestURL();
request.setAttribute("requestUrl", requestUrl.toString());
request.setAttribute("dataRef", request.getParameter("ref"));
request.setAttribute("filename", downloadableContent.getFilename());
request.setAttribute("contentType", mimeType);
@ -148,8 +156,6 @@ public class ContentViewerController extends HttpServlet {
request.getRequestDispatcher("/WEB-INF/jsp/header.jsp").include(request, response);
// remove the attributes needed for the header
request.removeAttribute("requestUrl");
request.removeAttribute("dataRef");
request.removeAttribute("filename");
request.removeAttribute("contentType");

View File

@ -31,8 +31,8 @@
<script type="text/javascript">
var $$ = $.noConflict(true);
$$(document).ready(function () {
var url = '${requestUrl}';
var ref = '${param.ref}';
var url = $$('#requestUrl').text();
var ref = $$('#ref').text();
// create the parameters
var params = {
@ -40,14 +40,14 @@
};
// include the cluster node if appropriate
var clusterNodeId = '${param.clusterNodeId}';
if (clusterNodeId !== null && clusterNodeId !== '') {
var clusterNodeId = $$('#clusterNodeId').text();
if (clusterNodeId !== '') {
params['clusterNodeId'] = clusterNodeId;
}
// determine the appropriate mode to select initially
var initialMode = '${param.mode}';
if (initialMode === null && initialMode === '') {
var initialMode = $$('#mode').text();
if (initialMode === '') {
initialMode = 'Original';
}
@ -85,8 +85,12 @@
</script>
</head>
<body class="message-pane">
<span id="ref" class="hidden"><%= org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("ref")) %></span>
<span id="clusterNodeId" class="hidden"><%= request.getParameter("clusterNodeId") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("clusterNodeId")) %></span>
<span id="mode" class="hidden"><%= request.getParameter("mode") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("mode")) %></span>
<span id="requestUrl" class="hidden"><%= org.apache.nifi.util.EscapeUtils.escapeHtml(request.getRequestURL().toString()) %></span>
<div id="view-as-label">View as</div>
<div id="view-as" class="pointer button-normal"></div>
<div id="content-filename"><span class="content-label">filename</span>${filename}</div>
<div id="content-type"><span class="content-label">content type</span>${contentType}</div>
<div id="content-filename"><span class="content-label">filename</span><%= request.getAttribute("filename") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("filename").toString()) %></div>
<div id="content-type"><span class="content-label">content type</span><%= request.getAttribute("contentType") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("contentType").toString()) %></div>
<div class="message-pane-message-box">

View File

@ -148,7 +148,7 @@ $(document).ready(function () {
$("table", div).addClass("hexviewerwindow_table");
$("table", div).append("<tr></tr>").addClass("hexviewerwindow");
$("table tr:last", div).append("<td>" + (decimal_offset ? ("00000000"+offset).slice(-8) : "0x" + dec_to_hex8(offset)) + "</td>");
$("table tr:last", div).append("<td>" + escapeHtml((decimal_offset ? ("00000000"+offset).slice(-8) : "0x" + dec_to_hex8(offset))) + "</td>");
$("table tr td:last", div).addClass("hexviewerwindow_offset");
var runlen = 0;
@ -162,7 +162,7 @@ $(document).ready(function () {
num += dec2_to_hex(line_data.charCodeAt(i+j));
}
$("table tr:last", div).append("<td>" + (hide_0x ? "" : "0x") + num + "</td>");
$("table tr:last", div).append("<td>" + escapeHtml((hide_0x ? "" : "0x") + num) + "</td>");
apply_highlights(offset+i);
}

View File

@ -26,12 +26,18 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-nar-utils</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>

View File

@ -30,7 +30,7 @@
<body id="documentation-body">
<div id="banner-header" class="main-banner-header"></div>
<div id="banner-footer" class="main-banner-footer"></div>
<span id="initial-selection" style="display: none;">${param.select}</span>
<span id="initial-selection" style="display: none;"><%= request.getParameter("select") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("select")) %></span>
<div id="documentation-header" class="documentation-header">
<div id="nf-title">NiFi Documentation</div>
<div id="nf-version"></div>

View File

@ -14,6 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* global top */
$(document).ready(function () {
var isUndefined = function (obj) {
@ -139,7 +142,7 @@ $(document).ready(function () {
if (isDefinedAndNotNull(response.banners)) {
if (isDefinedAndNotNull(response.banners.headerText) && response.banners.headerText !== '') {
// update the header text
var bannerHeader = $('#banner-header').html(response.banners.headerText).show();
var bannerHeader = $('#banner-header').text(response.banners.headerText).show();
// show the banner
var updateTop = function (elementId) {
@ -155,7 +158,7 @@ $(document).ready(function () {
if (isDefinedAndNotNull(response.banners.footerText) && response.banners.footerText !== '') {
// update the footer text and show it
var bannerFooter = $('#banner-footer').html(response.banners.footerText).show();
var bannerFooter = $('#banner-footer').text(response.banners.footerText).show();
var updateBottom = function (elementId) {
var element = $('#' + elementId);

View File

@ -79,6 +79,7 @@
<packageRoot>org.apache.nifi.web.jsp</packageRoot>
<keepSources>true</keepSources>
<verbose>true</verbose>
<useProvidedScope>true</useProvidedScope>
<excludes>
**/canvas.jsp,
**/summary.jsp,
@ -619,6 +620,11 @@
<artifactId>commons-io</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>

View File

@ -18,7 +18,7 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>${title}</title>
<title><%= request.getAttribute("title") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("title").toString()) %></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="shortcut icon" href="images/nifi16.ico"/>
<link href="/nifi/css/message-pane.css" rel="stylesheet" type="text/css" />
@ -27,8 +27,8 @@
<body class="message-pane">
<div class="message-pane-message-box">
<p class="message-pane-title">${title}</p>
<p class="message-pane-content">${messages}</p>
<p class="message-pane-title"><%= request.getAttribute("title") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("title").toString()) %></p>
<p class="message-pane-content"><%= request.getAttribute("messages") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("messages").toString()) %></p>
</div>
</body>
</html>

View File

@ -28,6 +28,11 @@
<artifactId>commons-lang3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>

View File

@ -20,13 +20,16 @@
<script type="text/javascript" src="../nifi/js/codemirror/lib/codemirror-compressed.js"></script>
<script type="text/javascript" src="../nifi/js/jquery/jquery-2.1.1.min.js"></script>
<textarea id="codemirror-content">${content}</textarea>
<textarea id="codemirror-content"><%= request.getAttribute("content") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("content").toString()) %></textarea>
<span id="codemirror-mode" style="display: none;"><%= org.apache.nifi.util.EscapeUtils.escapeHtml(request.getAttribute("mode").toString()) %></span>
<script type="text/javascript">
$(document).ready(function() {
var mode = $('#codemirror-mode').text();
var field = document.getElementById('codemirror-content');
var editor = CodeMirror.fromTextArea(field, {
mode: '${mode}',
mode: mode,
lineNumbers: true,
matchBrackets: true,
foldGutter: true,

View File

@ -33,6 +33,11 @@
<artifactId>nifi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-custom-ui-utilities</artifactId>

View File

@ -59,10 +59,10 @@
<title>Update Attribute</title>
</head>
<body>
<div id="attribute-updater-processor-id" class="hidden">${param.id}</div>
<div id="attribute-updater-client-id" class="hidden">${param.clientId}</div>
<div id="attribute-updater-revision" class="hidden">${param.revision}</div>
<div id="attribute-updater-editable" class="hidden">${param.editable}</div>
<div id="attribute-updater-processor-id" class="hidden"><%= request.getParameter("id") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("id")) %></div>
<div id="attribute-updater-client-id" class="hidden"><%= request.getParameter("clientId") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("clientId")) %></div>
<div id="attribute-updater-revision" class="hidden"><%= request.getParameter("revision") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("revision")) %></div>
<div id="attribute-updater-editable" class="hidden"><%= request.getParameter("editable") == null ? "" : org.apache.nifi.util.EscapeUtils.escapeHtml(request.getParameter("editable")) %></div>
<div id="update-attributes-content">
<div id="rule-list-panel">
<div id="flowfile-policy-container">