You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mo...@apache.org on 2017/05/11 17:33:24 UTC
[22/39] nifi git commit: - 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.
- 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/support/nifi-0.7.x
Commit: fd6eb669efcf27d3148b624355e2916d3c3e55a5
Parents: 5593be4
Author: Matt Gilman <ma...@gmail.com>
Authored: Tue Feb 14 16:11:05 2017 -0500
Committer: Matt Gilman <ma...@gmail.com>
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 {
* <CN=original-proxied-entity><CN=first-proxy><CN=second-proxy>...
* </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 {
* <CN=original-proxied-entity><CN=first-proxy><CN=second-proxy>...
* </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 "