Repository: nifi
Updated Branches:
  refs/heads/0.x 5593be400 -> fd6eb669e


- Setting the user details in the web cluster manager and removing unnecessary 
code.
- Deprecating the unnecessary methods.
- Code clean up.
- Fixing checkstyle issues in PutKafka.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/fd6eb669
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/fd6eb669
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/fd6eb669

Branch: refs/heads/0.x
Commit: fd6eb669efcf27d3148b624355e2916d3c3e55a5
Parents: 5593be4
Author: Matt Gilman <[email protected]>
Authored: Tue Feb 14 16:11:05 2017 -0500
Committer: Matt Gilman <[email protected]>
Committed: Tue Feb 14 16:33:56 2017 -0500

----------------------------------------------------------------------
 .../apache/nifi/web/NiFiWebContextConfig.java   |   5 +
 .../apache/nifi/web/NiFiWebRequestContext.java  |   5 +
 .../cluster/manager/impl/WebClusterManager.java | 129 +++++-----
 .../nifi/web/HttpServletRequestContext.java     |  39 +--
 .../web/HttpServletRequestContextConfig.java    |  40 +---
 .../nifi/web/StandardNiFiContentAccess.java     |  21 --
 .../StandardNiFiWebConfigurationContext.java    |  22 --
 .../apache/nifi/web/StandardNiFiWebContext.java |  60 ++---
 .../nifi/web/api/ApplicationResource.java       |  24 --
 .../apache/nifi/web/ContentRequestContext.java  |   5 +
 .../nifi/web/ContentViewerController.java       |  23 +-
 .../web/security/NiFiAuthenticationFilter.java  |  24 +-
 .../nifi/web/security/ProxiedEntitiesUtils.java | 134 +++++++----
 .../security/ProxiedEntitiesUtilsTest.groovy    | 235 +++++++++++++++++++
 .../apache/nifi/processors/kafka/PutKafka.java  |  35 ++-
 15 files changed, 472 insertions(+), 329 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java 
b/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
index 2df94e4..c86599f 100644
--- a/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
+++ b/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
@@ -48,8 +48,13 @@ public interface NiFiWebContextConfig {
      * 
&lt;CN=original-proxied-entity&gt;&lt;CN=first-proxy&gt;&lt;CN=second-proxy&gt;...
      * </code>
      *
+     * Update:
+     * This method has been deprecated since the entire proxy
+     * chain is able to be rebuilt using the current user if necessary.
+     *
      * @return the proxied entities chain or null if no chain
      */
+    @Deprecated
     String getProxiedEntitiesChain();
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java 
b/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
index 9dd44ab..bb3bbd3 100644
--- a/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
+++ b/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
@@ -49,8 +49,13 @@ public interface NiFiWebRequestContext {
      * 
&lt;CN=original-proxied-entity&gt;&lt;CN=first-proxy&gt;&lt;CN=second-proxy&gt;...
      * </code>
      *
+     * Update:
+     * This method has been deprecated since the entire proxy
+     * chain is able to be rebuilt using the current user if necessary.
+     *
      * @return the proxied entities chain or null if no chain
      */
+    @Deprecated
     String getProxiedEntitiesChain();
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
index b74ea50..fc0f10f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
@@ -16,58 +16,7 @@
  */
 package org.apache.nifi.cluster.manager.impl;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.NavigableSet;
-import java.util.Queue;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.UUID;
-import java.util.concurrent.CompletionService;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.regex.Pattern;
-
-import javax.net.ssl.SSLContext;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.StreamingOutput;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
+import com.sun.jersey.api.client.ClientResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.admin.service.AuditService;
 import org.apache.nifi.annotation.lifecycle.OnAdded;
@@ -246,9 +195,13 @@ import 
org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
 import org.apache.nifi.web.api.entity.RemoteProcessGroupsEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskEntity;
 import org.apache.nifi.web.api.entity.ReportingTasksEntity;
+import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
+import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -256,7 +209,56 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
-import com.sun.jersey.api.client.ClientResponse;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.StreamingOutput;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Queue;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.regex.Pattern;
 
 /**
  * Provides a cluster manager implementation. The manager federates incoming 
HTTP client requests to the nodes' external API using the HTTP protocol. The 
manager also communicates with nodes using the
@@ -2327,12 +2329,31 @@ public class WebClusterManager implements 
HttpClusterManager, ProtocolHandler, C
         // check if this request can change the flow
         final boolean mutableRequest = canChangeNodeState(method, uri);
 
+        // include the user details
+        final Map<String, String> headersWithUserDetails = new 
HashMap<>(headers);
+
+        // add the user's authorities (if any) to the headers
+        final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
+        if (authentication != null) {
+            final Object userDetailsObj = authentication.getPrincipal();
+            if (userDetailsObj instanceof NiFiUserDetails) {
+                // serialize user details object
+                final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
+
+                // put serialized user details in header
+                headersWithUserDetails.put("X-ProxiedEntityUserDetails", 
hexEncodedUserDetails);
+
+                // remove the access token if present, since the user is 
already authenticated/authorized
+                
headersWithUserDetails.remove(JwtAuthenticationFilter.AUTHORIZATION);
+            }
+        }
+
         final ObjectHolder<NodeResponse> holder = new ObjectHolder<>(null);
         final UpdateRevision federateRequest = new UpdateRevision() {
             @Override
             public Revision execute(Revision currentRevision) {
                 // update headers to contain cluster contextual information to 
send to the node
-                final Map<String, String> updatedHeaders = new 
HashMap<>(headers);
+                final Map<String, String> updatedHeaders = new 
HashMap<>(headersWithUserDetails);
                 final ClusterContext clusterCtx = new ClusterContextImpl();
                 clusterCtx.setRequestSentByClusterManager(true);               
  // indicate request is sent from cluster manager
                 clusterCtx.setRevision(currentRevision);

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContext.java
index 311fbc7..d8d5860 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContext.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContext.java
@@ -16,7 +16,6 @@
  */
 package org.apache.nifi.web;
 
-import java.security.cert.X509Certificate;
 import javax.servlet.http.HttpServletRequest;
 
 /**
@@ -42,19 +41,7 @@ public class HttpServletRequestContext implements 
NiFiWebRequestContext {
 
     @Override
     public String getProxiedEntitiesChain() {
-        String xProxiedEntitiesChain = 
request.getHeader("X-ProxiedEntitiesChain");
-        final X509Certificate cert = extractClientCertificate(request);
-        if (cert != null) {
-            final String extractedPrincipal = extractPrincipal(cert);
-            final String formattedPrincipal = 
formatProxyDn(extractedPrincipal);
-            if (xProxiedEntitiesChain == null || 
xProxiedEntitiesChain.trim().isEmpty()) {
-                xProxiedEntitiesChain = formattedPrincipal;
-            } else {
-                xProxiedEntitiesChain += formattedPrincipal;
-            }
-        }
-
-        return xProxiedEntitiesChain;
+        return null;
     }
 
     /**
@@ -73,28 +60,4 @@ public class HttpServletRequestContext implements 
NiFiWebRequestContext {
     public String getId() {
         return request.getParameter(ID_PARAM);
     }
-
-    /**
-     * Utility methods that have been copied into this class to reduce the
-     * dependency footprint of this artifact. These utility methods typically
-     * live in web-utilities but that would pull in spring, jersey, jackson,
-     * etc.
-     */
-    private X509Certificate extractClientCertificate(HttpServletRequest 
request) {
-        X509Certificate[] certs = (X509Certificate[]) 
request.getAttribute("javax.servlet.request.X509Certificate");
-
-        if (certs != null && certs.length > 0) {
-            return certs[0];
-        }
-
-        return null;
-    }
-
-    private String extractPrincipal(X509Certificate cert) {
-        return cert.getSubjectDN().getName().trim();
-    }
-
-    private String formatProxyDn(String dn) {
-        return "<" + dn + ">";
-    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
index e376ab6..009289d 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
@@ -16,7 +16,6 @@
  */
 package org.apache.nifi.web;
 
-import java.security.cert.X509Certificate;
 import javax.servlet.http.HttpServletRequest;
 
 /**
@@ -40,20 +39,7 @@ public class HttpServletRequestContextConfig implements 
NiFiWebContextConfig {
 
     @Override
     public String getProxiedEntitiesChain() {
-
-        String xProxiedEntitiesChain = 
request.getHeader("X-ProxiedEntitiesChain");
-        final X509Certificate cert = extractClientCertificate(request);
-        if (cert != null) {
-            final String extractedPrincipal = extractPrincipal(cert);
-            final String formattedPrincipal = 
formatProxyDn(extractedPrincipal);
-            if (xProxiedEntitiesChain == null || 
xProxiedEntitiesChain.trim().isEmpty()) {
-                xProxiedEntitiesChain = formattedPrincipal;
-            } else {
-                xProxiedEntitiesChain += formattedPrincipal;
-            }
-        }
-
-        return xProxiedEntitiesChain;
+        return null;
     }
 
     /**
@@ -92,28 +78,4 @@ public class HttpServletRequestContextConfig implements 
NiFiWebContextConfig {
 
         return new Revision(revision, clientId);
     }
-
-    /**
-     * Utility methods that have been copied into this class to reduce the
-     * dependency footprint of this artifact. These utility methods typically
-     * live in web-utilities but that would pull in spring, jersey, jackson,
-     * etc.
-     */
-    private X509Certificate extractClientCertificate(HttpServletRequest 
request) {
-        X509Certificate[] certs = (X509Certificate[]) 
request.getAttribute("javax.servlet.request.X509Certificate");
-
-        if (certs != null && certs.length > 0) {
-            return certs[0];
-        }
-
-        return null;
-    }
-
-    private String extractPrincipal(X509Certificate cert) {
-        return cert.getSubjectDN().getName().trim();
-    }
-
-    private String formatProxyDn(String dn) {
-        return "<" + dn + ">";
-    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
index afaf3ed..5ff82aa 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
@@ -28,18 +28,13 @@ import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.controller.repository.claim.ContentDirection;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 
 import javax.ws.rs.HttpMethod;
 import javax.ws.rs.core.MultivaluedMap;
-import java.io.Serializable;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashMap;
@@ -85,22 +80,6 @@ public class StandardNiFiContentAccess implements 
ContentAccess {
 
             // set the headers
             final Map<String, String> headers = new HashMap<>();
-            if (StringUtils.isNotBlank(request.getProxiedEntitiesChain())) {
-                headers.put("X-ProxiedEntitiesChain", 
request.getProxiedEntitiesChain());
-            }
-
-            // add the user's authorities (if any) to the headers
-            final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
-            if (authentication != null) {
-                final Object userDetailsObj = authentication.getPrincipal();
-                if (userDetailsObj instanceof NiFiUserDetails) {
-                    // serialize user details object
-                    final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
-
-                    // put serialized user details in header
-                    headers.put("X-ProxiedEntityUserDetails", 
hexEncodedUserDetails);
-                }
-            }
 
             // ensure we were able to detect the cluster node id
             if (request.getClusterNodeId() == null) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
index d1d0796..fb59565 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
@@ -44,22 +44,16 @@ import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.ControllerServiceEntity;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskEntity;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.util.ClientResponseUtils;
-import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 
 import javax.ws.rs.HttpMethod;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
-
 import java.io.IOException;
-import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -803,22 +797,6 @@ public class StandardNiFiWebConfigurationContext 
implements NiFiWebConfiguration
     private Map<String, String> getHeaders(final NiFiWebRequestContext config) 
{
         final Map<String, String> headers = new HashMap<>();
         headers.put("Accept", "application/json,application/xml");
-        if (StringUtils.isNotBlank(config.getProxiedEntitiesChain())) {
-            headers.put("X-ProxiedEntitiesChain", 
config.getProxiedEntitiesChain());
-        }
-
-        // add the user's authorities (if any) to the headers
-        final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
-        if (authentication != null) {
-            final Object userDetailsObj = authentication.getPrincipal();
-            if (userDetailsObj instanceof NiFiUserDetails) {
-                // serialize user details object
-                final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
-
-                // put serialized user details in header
-                headers.put("X-ProxiedEntityUserDetails", 
hexEncodedUserDetails);
-            }
-        }
         return headers;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
index 96ed822..504926f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
@@ -16,22 +16,8 @@
  */
 package org.apache.nifi.web;
 
-import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URLEncoder;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.action.Action;
 import org.apache.nifi.action.Component;
 import org.apache.nifi.action.FlowChangeAction;
@@ -42,26 +28,32 @@ import org.apache.nifi.admin.service.AuditService;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.controller.ControllerService;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
+import org.apache.nifi.controller.ControllerServiceLookup;
 import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
-import org.apache.nifi.web.util.WebUtils;
-
-import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.web.security.user.NiFiUserUtils;
+import org.apache.nifi.web.util.ClientResponseUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 
-import com.sun.jersey.core.util.MultivaluedMapImpl;
-import org.apache.nifi.controller.ControllerServiceLookup;
-import org.apache.nifi.web.util.ClientResponseUtils;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * Implements the NiFiWebContext interface to support a context in both 
standalone and clustered environments.
@@ -297,22 +289,6 @@ public class StandardNiFiWebContext implements 
NiFiWebContext {
     private Map<String, String> getHeaders(final NiFiWebContextConfig config) {
         final Map<String, String> headers = new HashMap<>();
         headers.put("Accept", "application/json,application/xml");
-        if (StringUtils.isNotBlank(config.getProxiedEntitiesChain())) {
-            headers.put("X-ProxiedEntitiesChain", 
config.getProxiedEntitiesChain());
-        }
-
-        // add the user's authorities (if any) to the headers
-        final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
-        if (authentication != null) {
-            final Object userDetailsObj = authentication.getPrincipal();
-            if (userDetailsObj instanceof NiFiUserDetails) {
-                // serialize user details object
-                final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
-
-                // put serialized user details in header
-                headers.put("X-ProxiedEntityUserDetails", 
hexEncodedUserDetails);
-            }
-        }
         return headers;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
index 6f895b8..77a00be 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
@@ -32,13 +32,9 @@ import 
org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.entity.Entity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -72,8 +68,6 @@ public abstract class ApplicationResource {
     public static final String PROXY_HOST_HTTP_HEADER = "X-ProxyHost";
     public static final String PROXY_PORT_HTTP_HEADER = "X-ProxyPort";
     public static final String PROXY_CONTEXT_PATH_HTTP_HEADER = 
"X-ProxyContextPath";
-    public static final String PROXIED_ENTITIES_CHAIN_HTTP_HEADER = 
"X-ProxiedEntitiesChain";
-    public static final String PROXIED_ENTITY_USER_DETAILS_HTTP_HEADER = 
"X-ProxiedEntityUserDetails";
 
     private static final int HEADER_BUFFER_SIZE = 16 * 1024; // 16kb
     private static final int CLUSTER_CONTEXT_HEADER_VALUE_MAX_BYTES = (int) 
(0.75 * HEADER_BUFFER_SIZE);
@@ -372,24 +366,6 @@ public abstract class ApplicationResource {
             result.put(PROXY_SCHEME_HTTP_HEADER, 
httpServletRequest.getScheme());
         }
 
-        if (httpServletRequest.isSecure()) {
-
-            // add the user's authorities (if any) to the headers
-            final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
-            if (authentication != null) {
-                final Object userDetailsObj = authentication.getPrincipal();
-                if (userDetailsObj instanceof NiFiUserDetails) {
-                    // serialize user details object
-                    final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
-
-                    // put serialized user details in header
-                    result.put(PROXIED_ENTITY_USER_DETAILS_HTTP_HEADER, 
hexEncodedUserDetails);
-
-                    // remove the access token if present, since the user is 
already authenticated/authorized
-                    result.remove(JwtAuthenticationFilter.AUTHORIZATION);
-                }
-            }
-        }
         return result;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-access/src/main/java/org/apache/nifi/web/ContentRequestContext.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-access/src/main/java/org/apache/nifi/web/ContentRequestContext.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-access/src/main/java/org/apache/nifi/web/ContentRequestContext.java
index 6154576..a7d83e3 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-access/src/main/java/org/apache/nifi/web/ContentRequestContext.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-access/src/main/java/org/apache/nifi/web/ContentRequestContext.java
@@ -45,7 +45,12 @@ public interface ContentRequestContext {
     /**
      * The proxy chain for the current request, if applicable.
      *
+     * Update:
+     * This method has been deprecated since the entire proxy
+     * chain is able to be rebuilt using the current user if necessary.
+     *
      * @return the proxied entities chain
      */
+    @Deprecated
     String getProxiedEntitiesChain();
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
index 50ca101..eda65e4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
@@ -18,16 +18,6 @@ package org.apache.nifi.web;
 
 import com.ibm.icu.text.CharsetDetector;
 import com.ibm.icu.text.CharsetMatch;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -41,6 +31,16 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
 
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
 /**
  * Controller servlet for viewing content. This is responsible for generating
  * the markup for the header and footer of the page. Included in that is the
@@ -299,7 +299,6 @@ public class ContentViewerController extends HttpServlet {
     private ContentRequestContext getContentRequest(final HttpServletRequest 
request) {
         final String ref = request.getParameter("ref");
         final String clientId = request.getParameter("clientId");
-        final String proxiedEntitiesChain = 
request.getHeader("X-ProxiedEntitiesChain");
 
         final URI refUri = URI.create(ref);
         final String query = refUri.getQuery();
@@ -334,7 +333,7 @@ public class ContentViewerController extends HttpServlet {
 
             @Override
             public String getProxiedEntitiesChain() {
-                return proxiedEntitiesChain;
+                return null;
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
index 4b4c66a..d217532 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
@@ -16,14 +16,6 @@
  */
 package org.apache.nifi.web.security;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
@@ -40,6 +32,16 @@ import 
org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.web.filter.GenericFilterBean;
 
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+
 /**
  *
  */
@@ -85,7 +87,7 @@ public abstract class NiFiAuthenticationFilter extends 
GenericFilterBean {
         try {
             final NiFiAuthorizationRequestToken authenticated = 
attemptAuthentication(request);
             if (authenticated != null) {
-                dnChain = 
ProxiedEntitiesUtils.formatProxyDn(StringUtils.join(authenticated.getChain(), 
"><"));
+                dnChain = formatProxyChain(authenticated.getChain());
 
                 // log the request attempt - response details will be logged 
later
                 log.info(String.format("Attempting request for (%s) %s %s 
(source ip: %s)", dnChain, request.getMethod(),
@@ -117,6 +119,10 @@ public abstract class NiFiAuthenticationFilter extends 
GenericFilterBean {
         }
     }
 
+    private String formatProxyChain(final List<String> dnChain) {
+        return "<" + StringUtils.join(dnChain, "><") + ">";
+    }
+
     /**
      * Attempt to authenticate the client making the request. If the request 
does not contain an authentication attempt, this method should return null. If 
the request contains an authentication
      * request, the implementation should convert it to a 
NiFiAuthorizationRequestToken (which is used when authorizing the client). 
Implementations should throw InvalidAuthenticationException when

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
index 1b2f28a..3fb883e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
@@ -16,27 +16,34 @@
  */
 package org.apache.nifi.web.security;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.user.NiFiUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  *
  */
 public class ProxiedEntitiesUtils {
 
+    private static final Logger logger = 
LoggerFactory.getLogger(ProxiedEntitiesUtils.class);
+
     public static final String PROXY_ENTITIES_CHAIN = "X-ProxiedEntitiesChain";
     public static final String PROXY_ENTITIES_ACCEPTED = 
"X-ProxiedEntitiesAccepted";
     public static final String PROXY_ENTITIES_DETAILS = 
"X-ProxiedEntitiesDetails";
 
-    private static final Pattern proxyChainPattern = 
Pattern.compile("<(.*?)>");
+    private static final String GT = ">";
+    private static final String ESCAPED_GT = "\\\\>";
+    private static final String LT = "<";
+    private static final String ESCAPED_LT = "\\\\<";
 
     /**
      * Formats the specified DN to be set as a HTTP header using well known 
conventions.
@@ -45,7 +52,51 @@ public class ProxiedEntitiesUtils {
      * @return the dn formatted as an HTTP header
      */
     public static String formatProxyDn(String dn) {
-        return "<" + dn + ">";
+        return LT + sanitizeDn(dn) + GT;
+    }
+
+    /**
+     * If a user provides a DN with the sequence '><', they could escape the 
tokenization process and impersonate another user.
+     * <p>
+     * Example:
+     * <p>
+     * Provided DN: {@code tom><alopresto} -> {@code 
<tom><alopresto><proxy...>} would allow the user to impersonate tom
+     *
+     * @param rawDn the unsanitized DN
+     * @return the sanitized DN
+     */
+    private static String sanitizeDn(String rawDn) {
+        if (StringUtils.isEmpty(rawDn)) {
+            return rawDn;
+        } else {
+            String sanitizedDn = rawDn.replaceAll(GT, 
ESCAPED_GT).replaceAll(LT, ESCAPED_LT);
+            if (!sanitizedDn.equals(rawDn)) {
+                logger.warn("The provided DN [" + rawDn + "] contained 
dangerous characters that were escaped to [" + sanitizedDn + "]");
+            }
+            return sanitizedDn;
+        }
+    }
+
+    /**
+     * Reconstitutes the original DN from the sanitized version passed in the 
proxy chain.
+     * <p>
+     * Example:
+     * <p>
+     * {@code tom\>\<proxy1} -> {@code tom><proxy1}
+     *
+     * @param sanitizedDn the sanitized DN
+     * @return the original DN
+     */
+    private static String unsanitizeDn(String sanitizedDn) {
+        if (StringUtils.isEmpty(sanitizedDn)) {
+            return sanitizedDn;
+        } else {
+            String unsanitizedDn = sanitizedDn.replaceAll(ESCAPED_GT, 
GT).replaceAll(ESCAPED_LT, LT);
+            if (!unsanitizedDn.equals(sanitizedDn)) {
+                logger.warn("The provided DN [" + sanitizedDn + "] had been 
escaped, and was reconstituted to the dangerous DN [" + unsanitizedDn + "]");
+            }
+            return unsanitizedDn;
+        }
     }
 
     /**
@@ -56,9 +107,27 @@ public class ProxiedEntitiesUtils {
      */
     public static List<String> tokenizeProxiedEntitiesChain(String 
rawProxyChain) {
         final List<String> proxyChain = new ArrayList<>();
-        final Matcher rawProxyChainMatcher = 
proxyChainPattern.matcher(rawProxyChain);
-        while (rawProxyChainMatcher.find()) {
-            proxyChain.add(rawProxyChainMatcher.group(1));
+        if (!StringUtils.isEmpty(rawProxyChain)) {
+            // Split the String on the >< token
+            List<String> elements = 
Arrays.asList(StringUtils.splitByWholeSeparatorPreserveAllTokens(rawProxyChain, 
"><"));
+
+            // Unsanitize each DN and collect back
+            List<String> unsanitizedElements = new 
ArrayList<>(elements.size());
+            for (final String element : elements) {
+                unsanitizedElements.add(unsanitizeDn(element));
+            }
+
+            // Remove the leading < from the first element
+            unsanitizedElements.set(0, 
unsanitizedElements.get(0).replaceFirst(LT, ""));
+
+            // Remove the trailing > from the last element
+            int last = unsanitizedElements.size() - 1;
+            String lastElement = unsanitizedElements.get(last);
+            if (lastElement.endsWith(GT)) {
+                unsanitizedElements.set(last, lastElement.substring(0, 
lastElement.length() - 1));
+            }
+
+            proxyChain.addAll(unsanitizedElements);
         }
 
         return proxyChain;
@@ -68,18 +137,6 @@ public class ProxiedEntitiesUtils {
      * Builds the proxy chain for the specified user.
      *
      * @param user The current user
-     * @return The proxy chain for that user in String form
-     */
-    public static String buildProxiedEntitiesChainString(final NiFiUser user) {
-        // calculate the dn chain
-        final List<String> proxyChain = buildProxiedEntitiesChain(user);
-        return formatProxyDn(StringUtils.join(proxyChain, "><"));
-    }
-
-    /**
-     * Builds the proxy chain for the specified user.
-     *
-     * @param user The current user
      * @return The proxy chain for that user in List form
      */
     public static List<String> buildProxiedEntitiesChain(final NiFiUser user) {
@@ -88,13 +145,13 @@ public class ProxiedEntitiesUtils {
 
         // build the dn chain
         NiFiUser chainedUser = user;
-        do {
+        while (chainedUser != null) {
             // add the entry for this user
             proxyChain.add(chainedUser.getIdentity());
 
             // go to the next user in the chain
             chainedUser = chainedUser.getChain();
-        } while (chainedUser != null);
+        }
 
         return proxyChain;
     }
@@ -107,30 +164,9 @@ public class ProxiedEntitiesUtils {
      * @return the proxy chain in list form
      */
     public static List<String> buildProxiedEntitiesChain(final 
HttpServletRequest request, final String username) {
-        final String chain = buildProxiedEntitiesChainString(request, 
username);
-        return tokenizeProxiedEntitiesChain(chain);
-    }
-
-    /**
-     * Builds the dn chain from the specified request and user.
-     *
-     * @param request the request
-     * @param username the username
-     * @return the dn chain in string form
-     */
-    public static String buildProxiedEntitiesChainString(final 
HttpServletRequest request, final String username) {
-        String principal;
-        if (username.startsWith("<") && username.endsWith(">")) {
-            principal = username;
-        } else {
-            principal = formatProxyDn(username);
-        }
-
-        // look for a proxied user
-        if (StringUtils.isNotBlank(request.getHeader(PROXY_ENTITIES_CHAIN))) {
-            principal = request.getHeader(PROXY_ENTITIES_CHAIN) + principal;
-        }
-        return principal;
+        final List<String> proxyChain = new 
ArrayList<>(tokenizeProxiedEntitiesChain(request.getHeader(PROXY_ENTITIES_CHAIN)));
+        proxyChain.add(username);
+        return proxyChain;
     }
 
     public static void successfulAuthorization(HttpServletRequest request, 
HttpServletResponse response, Authentication authResult) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/ProxiedEntitiesUtilsTest.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/ProxiedEntitiesUtilsTest.groovy
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/ProxiedEntitiesUtilsTest.groovy
new file mode 100644
index 0000000..f0511bd
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/ProxiedEntitiesUtilsTest.groovy
@@ -0,0 +1,235 @@
+/*
+ * 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.security
+
+import org.apache.nifi.user.NiFiUser
+import org.junit.After
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+@RunWith(JUnit4.class)
+class ProxiedEntitiesUtilsTest {
+    private static final Logger logger = 
LoggerFactory.getLogger(ProxiedEntitiesUtils.class)
+
+    private static final String SAFE_USER_NAME_ANDY = "alopresto"
+    private static final String SAFE_USER_DN_ANDY = 
"CN=${SAFE_USER_NAME_ANDY}, OU=Apache NiFi"
+
+    private static final String SAFE_USER_NAME_TOM = "tom"
+    private static final String SAFE_USER_DN_TOM = "CN=${SAFE_USER_NAME_TOM}, 
OU=Apache NiFi"
+
+    private static final String SAFE_USER_NAME_PROXY_1 = 
"proxy1.nifi.apache.org"
+    private static final String SAFE_USER_DN_PROXY_1 = 
"CN=${SAFE_USER_NAME_PROXY_1}, OU=Apache NiFi"
+
+    private static final String SAFE_USER_NAME_PROXY_2 = 
"proxy2.nifi.apache.org"
+    private static final String SAFE_USER_DN_PROXY_2 = 
"CN=${SAFE_USER_NAME_PROXY_2}, OU=Apache NiFi"
+
+    private static
+    final String MALICIOUS_USER_NAME_TOM = "${SAFE_USER_NAME_TOM}, OU=Apache 
NiFi><CN=${SAFE_USER_NAME_PROXY_1}"
+    private static final String MALICIOUS_USER_DN_TOM = 
"CN=${MALICIOUS_USER_NAME_TOM}, OU=Apache NiFi"
+
+    private static
+    final String MALICIOUS_USER_NAME_TOM_ESCAPED = 
sanitizeDn(MALICIOUS_USER_NAME_TOM)
+    private static final String MALICIOUS_USER_DN_TOM_ESCAPED = 
sanitizeDn(MALICIOUS_USER_DN_TOM)
+
+    @BeforeClass
+    static void setUpOnce() throws Exception {
+        logger.metaClass.methodMissing = { String name, args ->
+            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
+        }
+    }
+
+    @Before
+    void setUp() {
+    }
+
+    @After
+    void tearDown() {
+    }
+
+    private static String sanitizeDn(String dn = "") {
+        dn.replaceAll(/>/, '\\\\>').replaceAll('<', '\\\\<')
+    }
+
+    private static String printUnicodeString(final String raw) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < raw.size(); i++) {
+            int codePoint = Character.codePointAt(raw, i)
+            int charCount = Character.charCount(codePoint)
+            if (charCount > 1) {
+                i += charCount - 1 // 2.
+                if (i >= raw.length()) {
+                    throw new IllegalArgumentException("Code point indicated 
more characters than available")
+                }
+            }
+            sb.append(String.format("\\u%04x ", codePoint))
+        }
+        return sb.toString().trim()
+    }
+
+    @Test
+    void testSanitizeDnShouldHandleFuzzing() throws Exception {
+        // Arrange
+        final String DESIRED_NAME = SAFE_USER_NAME_TOM
+        logger.info("  Desired name: ${DESIRED_NAME} |  
${printUnicodeString(DESIRED_NAME)}")
+
+        // Contains various attempted >< escapes, trailing NULL, and BACKSPACE 
+ 'n'
+        final List MALICIOUS_NAMES = [MALICIOUS_USER_NAME_TOM,
+                                      SAFE_USER_NAME_TOM + ">",
+                                      SAFE_USER_NAME_TOM + "><>",
+                                      SAFE_USER_NAME_TOM + "\\>",
+                                      SAFE_USER_NAME_TOM + "\u003e",
+                                      SAFE_USER_NAME_TOM + 
"\u005c\u005c\u003e",
+                                      SAFE_USER_NAME_TOM + "\u0000",
+                                      SAFE_USER_NAME_TOM + "\u0008n"]
+
+        // Act
+        MALICIOUS_NAMES.each { String name ->
+            logger.info("      Raw name: ${name} | 
${printUnicodeString(name)}")
+            String sanitizedName = ProxiedEntitiesUtils.sanitizeDn(name)
+            logger.info("Sanitized name: ${sanitizedName} | 
${printUnicodeString(sanitizedName)}")
+
+            // Assert
+            assert sanitizedName != DESIRED_NAME
+        }
+    }
+
+    @Test
+    void testShouldFormatProxyDn() throws Exception {
+        // Arrange
+        final String DN = SAFE_USER_DN_TOM
+        logger.info(" Provided proxy DN: ${DN}")
+
+        final String EXPECTED_PROXY_DN = "<${DN}>"
+        logger.info(" Expected proxy DN: ${EXPECTED_PROXY_DN}")
+
+        // Act
+        String formattedProxyDn = ProxiedEntitiesUtils.formatProxyDn(DN)
+        logger.info("Formatted proxy DN: ${formattedProxyDn}")
+
+        // Assert
+        assert formattedProxyDn == EXPECTED_PROXY_DN
+    }
+
+    @Test
+    void testFormatProxyDnShouldHandleMaliciousInput() throws Exception {
+        // Arrange
+        final String DN = MALICIOUS_USER_DN_TOM
+        logger.info(" Provided proxy DN: ${DN}")
+
+        final String SANITIZED_DN = sanitizeDn(DN)
+        final String EXPECTED_PROXY_DN = "<${SANITIZED_DN}>"
+        logger.info(" Expected proxy DN: ${EXPECTED_PROXY_DN}")
+
+        // Act
+        String formattedProxyDn = ProxiedEntitiesUtils.formatProxyDn(DN)
+        logger.info("Formatted proxy DN: ${formattedProxyDn}")
+
+        // Assert
+        assert formattedProxyDn == EXPECTED_PROXY_DN
+    }
+
+    @Test
+    void testShouldTokenizeProxiedEntitiesChainWithUserNames() throws 
Exception {
+        // Arrange
+        final List NAMES = [SAFE_USER_NAME_TOM, SAFE_USER_NAME_PROXY_1, 
SAFE_USER_NAME_PROXY_2]
+        final String RAW_PROXY_CHAIN = "<${NAMES.join("><")}>"
+        logger.info(" Provided proxy chain: ${RAW_PROXY_CHAIN}")
+
+        // Act
+        def tokenizedNames = 
ProxiedEntitiesUtils.tokenizeProxiedEntitiesChain(RAW_PROXY_CHAIN)
+        logger.info("Tokenized proxy chain: ${tokenizedNames}")
+
+        // Assert
+        assert tokenizedNames == NAMES
+    }
+
+    @Test
+    void testShouldTokenizeProxiedEntitiesChainWithDNs() throws Exception {
+        // Arrange
+        final List DNS = [SAFE_USER_DN_TOM, SAFE_USER_DN_PROXY_1, 
SAFE_USER_DN_PROXY_2]
+        final String RAW_PROXY_CHAIN = "<${DNS.join("><")}>"
+        logger.info(" Provided proxy chain: ${RAW_PROXY_CHAIN}")
+
+        // Act
+        def tokenizedDns = 
ProxiedEntitiesUtils.tokenizeProxiedEntitiesChain(RAW_PROXY_CHAIN)
+        logger.info("Tokenized proxy chain: ${tokenizedDns.collect { 
"\"${it}\"" }}")
+
+        // Assert
+        assert tokenizedDns == DNS
+    }
+
+    @Test
+    void testTokenizeProxiedEntitiesChainShouldHandleMaliciousUser() throws 
Exception {
+        // Arrange
+        final List NAMES = [MALICIOUS_USER_NAME_TOM, SAFE_USER_NAME_PROXY_1, 
SAFE_USER_NAME_PROXY_2]
+        final String RAW_PROXY_CHAIN = "<${NAMES.collect { sanitizeDn(it) 
}.join("><")}>"
+        logger.info(" Provided proxy chain: ${RAW_PROXY_CHAIN}")
+
+        // Act
+        def tokenizedNames = 
ProxiedEntitiesUtils.tokenizeProxiedEntitiesChain(RAW_PROXY_CHAIN)
+        logger.info("Tokenized proxy chain: ${tokenizedNames.collect { 
"\"${it}\"" }}")
+
+        // Assert
+        assert tokenizedNames == NAMES
+        assert tokenizedNames.size() == NAMES.size()
+        assert !tokenizedNames.contains(SAFE_USER_NAME_TOM)
+    }
+
+    @Test
+    void testShouldBuildProxyChain() throws Exception {
+        // Arrange
+        def mockProxy1 = [getIdentity: { -> SAFE_USER_NAME_PROXY_1}, getChain: 
{ -> null}] as NiFiUser
+        def mockTom = [getIdentity: { -> SAFE_USER_NAME_TOM}, getChain: { -> 
mockProxy1}] as NiFiUser
+
+        // Act
+        List<String> proxiedEntitiesChain = 
ProxiedEntitiesUtils.buildProxiedEntitiesChain(mockTom)
+        logger.info("Proxied entities chain: ${proxiedEntitiesChain}")
+
+        // Assert
+        assert proxiedEntitiesChain == [SAFE_USER_NAME_TOM, 
SAFE_USER_NAME_PROXY_1]
+    }
+
+    @Test
+    void testShouldBuildProxyChainFromSingleUser() throws Exception {
+        // Arrange
+        def mockTom = [getIdentity: { -> SAFE_USER_NAME_TOM}, getChain: { -> 
null}] as NiFiUser
+
+        // Act
+        List<String> proxiedEntitiesChain = 
ProxiedEntitiesUtils.buildProxiedEntitiesChain(mockTom)
+        logger.info("Proxied entities chain: ${proxiedEntitiesChain}")
+
+        // Assert
+        assert proxiedEntitiesChain == [SAFE_USER_NAME_TOM]
+    }
+
+    @Test
+    void testBuildProxyChainFromNullUserShouldBeEmpty() throws Exception {
+        // Arrange
+
+        // Act
+        List<String> proxiedEntitiesChain = 
ProxiedEntitiesUtils.buildProxiedEntitiesChain(null)
+        logger.info("Proxied entities chain: ${proxiedEntitiesChain}")
+
+        // Assert
+        assert proxiedEntitiesChain == []
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/fd6eb669/nifi-nar-bundles/nifi-kafka-bundle/nifi-kafka-processors/src/main/java/org/apache/nifi/processors/kafka/PutKafka.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-kafka-bundle/nifi-kafka-processors/src/main/java/org/apache/nifi/processors/kafka/PutKafka.java
 
b/nifi-nar-bundles/nifi-kafka-bundle/nifi-kafka-processors/src/main/java/org/apache/nifi/processors/kafka/PutKafka.java
index 38ec20c..c5af063 100644
--- 
a/nifi-nar-bundles/nifi-kafka-bundle/nifi-kafka-processors/src/main/java/org/apache/nifi/processors/kafka/PutKafka.java
+++ 
b/nifi-nar-bundles/nifi-kafka-bundle/nifi-kafka-processors/src/main/java/org/apache/nifi/processors/kafka/PutKafka.java
@@ -16,23 +16,6 @@
  */
 package org.apache.nifi.processors.kafka;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Pattern;
-
 import org.apache.nifi.annotation.behavior.DynamicProperty;
 import org.apache.nifi.annotation.behavior.InputRequirement;
 import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
@@ -40,8 +23,6 @@ import 
org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.AllowableValue;
 import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.DataUnit;
 import org.apache.nifi.processor.ProcessContext;
@@ -52,6 +33,22 @@ import org.apache.nifi.processor.io.InputStreamCallback;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.processors.kafka.KafkaPublisher.KafkaPublisherResult;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
+
 @InputRequirement(Requirement.INPUT_REQUIRED)
 @Tags({ "Apache", "Kafka", "Put", "Send", "Message", "PubSub", "0.8.x"})
 @CapabilityDescription("Sends the contents of a FlowFile as a message to 
Apache Kafka, specifically for 0.8.x versions. The messages to send may be 
individual FlowFiles or may be delimited, using a "

Reply via email to