This is an automated email from the ASF dual-hosted git repository.

thenatog pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/master by this push:
     new e81960f  NIFI-7170: - Adding a flag to nifi.properties to disable 
anonymous authentication.
e81960f is described below

commit e81960f8e8a6bd446bb766a5fb2e00c7e2e973f8
Author: Matt Gilman <matt.c.gil...@gmail.com>
AuthorDate: Wed Feb 19 15:49:44 2020 -0500

    NIFI-7170:
    - Adding a flag to nifi.properties to disable anonymous authentication.
    
    NIFI-7170:
    - Fixing checkstyle issues.
    
    NIFI-7170:
    - Adding missing license header.
    
    NIFI-7170:
    - Initial PR feedback.
    
    NIFI-7170:
    - Fixing broken integration tests.
    - Creating new integration tests for verifying allowing and preventing 
anonymous access.
    
    NIFI-7170:
    - Ensuring the new anonymous authentication property is considered for 
proxied requests.
    
    NIFI-7170 - Fixed comment.
    
    Signed-off-by: Nathan Gough <thena...@gmail.com>
    
    This closes #4099.
---
 .../java/org/apache/nifi/util/NiFiProperties.java  |  15 +-
 .../src/main/asciidoc/administration-guide.adoc    |  12 +-
 .../tasks/NiFiPropertiesDiagnosticTask.java        |   1 +
 .../nifi-framework/nifi-resources/pom.xml          |   1 +
 .../src/main/resources/conf/nifi.properties        |   1 +
 .../nifi/web/NiFiWebApiSecurityConfiguration.java  |  25 +++-
 .../accesscontrol/AccessControlHelper.java         |  10 +-
 .../accesscontrol/ITAccessTokenEndpoint.java       | 166 ++++++---------------
 ...lper.java => OneWaySslAccessControlHelper.java} |  97 ++++--------
 .../anonymous/AbstractAnonymousUserTest.java       |  57 +++++++
 .../anonymous/ITAllowDirectAnonymousAccess.java    |  66 ++++++++
 .../anonymous/ITAllowProxiedAnonymousAccess.java   |  66 ++++++++
 .../anonymous/ITPreventDirectAnonymousAccess.java  |  56 +++++++
 .../anonymous/ITPreventProxiedAnonymousAccess.java |  57 +++++++
 .../nifi/integration/util/NiFiTestAuthorizer.java  |   5 +
 .../nifi-anonymous-allowed.properties              | 139 +++++++++++++++++
 ...java => NiFiAnonymousAuthenticationFilter.java} |  25 ++--
 .../NiFiAnonymousAuthenticationProvider.java       |  56 +++++++
 .../NiFiAnonymousAuthenticationRequestToken.java   |  60 ++++++++
 .../security/x509/X509AuthenticationProvider.java  |   7 +
 .../main/resources/nifi-web-security-context.xml   |   6 +
 .../NiFiAnonymousAuthenticationProviderTest.java   |  91 +++++++++++
 .../x509/X509AuthenticationProviderTest.java       |  50 ++++++-
 23 files changed, 853 insertions(+), 216 deletions(-)

diff --git 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index f0e8e6b..214d178 100644
--- 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -153,6 +153,7 @@ public abstract class NiFiProperties {
     public static final String SECURITY_TRUSTSTORE_TYPE = 
"nifi.security.truststoreType";
     public static final String SECURITY_TRUSTSTORE_PASSWD = 
"nifi.security.truststorePasswd";
     public static final String SECURITY_USER_AUTHORIZER = 
"nifi.security.user.authorizer";
+    public static final String SECURITY_ANONYMOUS_AUTHENTICATION = 
"nifi.security.allow.anonymous.authentication";
     public static final String SECURITY_USER_LOGIN_IDENTITY_PROVIDER = 
"nifi.security.user.login.identity.provider";
     public static final String SECURITY_OCSP_RESPONDER_URL = 
"nifi.security.ocsp.responder.url";
     public static final String SECURITY_OCSP_RESPONDER_CERTIFICATE = 
"nifi.security.ocsp.responder.certificate";
@@ -920,9 +921,18 @@ public abstract class NiFiProperties {
     }
 
     /**
+     * @return True if property value is 'true'; False otherwise.
+     */
+    public Boolean isAnonymousAuthenticationAllowed() {
+        final String anonymousAuthenticationAllowed = 
getProperty(SECURITY_ANONYMOUS_AUTHENTICATION, "false");
+
+        return "true".equalsIgnoreCase(anonymousAuthenticationAllowed);
+    }
+
+    /**
      * Returns whether an OpenId Connect (OIDC) URL is set.
      *
-     * @return whether an OpenId Connection URL is set
+     * @return whether an OpenId Connect URL is set
      */
     public boolean isOidcEnabled() {
         return !StringUtils.isBlank(getOidcDiscoveryUrl());
@@ -1066,12 +1076,13 @@ public abstract class NiFiProperties {
      * - Kerberos service support is not enabled
      * - openid connect is not enabled
      * - knox sso is not enabled
+     * - anonymous authentication is not enabled
      * </p>
      *
      * @return true if client certificates are required for access to the REST 
API
      */
     public boolean isClientAuthRequiredForRestApi() {
-        return !isLoginIdentityProviderEnabled() && 
!isKerberosSpnegoSupportEnabled() && !isOidcEnabled() && !isKnoxSsoEnabled();
+        return !isLoginIdentityProviderEnabled() && 
!isKerberosSpnegoSupportEnabled() && !isOidcEnabled() && !isKnoxSsoEnabled() && 
!isAnonymousAuthenticationAllowed();
     }
 
     public InetSocketAddress getNodeApiAddress() {
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc 
b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 0b941bc..a3864f0 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -231,7 +231,16 @@ token during authentication.
 NOTE: NiFi can only be configured for username/password, OpenId Connect, or 
Apache Knox at a given time. It does not support running each of
 these concurrently. NiFi will require client certificates for authenticating 
users over HTTPS if none of these are configured.
 
-A secured instance of NiFi cannot be accessed anonymously unless configured to 
use an <<ldap_login_identity_provider>> or <<kerberos_login_identity_provider>> 
Login Identity Provider, which in turn must be configured to explicitly allow 
anonymous access. Anonymous access is not currently possible by the default 
FileAuthorizer (see <<authorizer-configuration>>), but is a future effort 
(link:https://issues.apache.org/jira/browse/NIFI-2730[NIFI-2730^]).
+A user cannot anonymously authenticate with a secured instance of NiFi unless 
`nifi.security.allow.anonymous.authentication` is set to `true`.
+If this is the case, NiFi must also be configured with an Authorizer that 
supports authorizing an anonymous user. Currently, NiFi does not ship
+with any Authorizers that support this. There is a feature request here to 
help support it 
(link:https://issues.apache.org/jira/browse/NIFI-2730[NIFI-2730^]).
+
+There are three scenarios to consider when setting 
`nifi.security.allow.anonymous.authentication`. When the user is directly 
calling an endpoint
+with no attempted authentication then 
`nifi.security.allow.anonymous.authentication` will control whether the request 
is authenticated or rejected.
+The other two scenarios are when the request is proxied. This could either be 
proxied by a NiFi node (e.g. a node in the NiFi cluster) or by a separate
+proxy that is proxying a request for an anonymous user. In these proxy 
scenarios `nifi.security.allow.anonymous.authentication` will control whether 
the
+request is authenticated or rejected. In all three of these scenarios if the 
request is authenticated it will subsequently be subjected to normal
+authorization based on the requested resource.
 
 NOTE: NiFi does not perform user authentication over HTTP. Using HTTP, all 
users will be granted all roles.
 
@@ -3289,6 +3298,7 @@ These properties pertain to various security features in 
NiFi. Many of these pro
 |`nifi.security.truststoreType`|The truststore type. It is blank by default.
 |`nifi.security.truststorePasswd`|The truststore password. It is blank by 
default.
 |`nifi.security.user.authorizer`|Specifies which of the configured Authorizers 
in the _authorizers.xml_ file to use.  By default, it is set to `file-provider`.
+|`nifi.security.allow.anonymous.authentication`|Whether anonymous 
authentication is allowed when running over HTTPS. If set to true, client 
certificates are not required to connect via TLS.
 |`nifi.security.user.login.identity.provider`|This indicates what type of 
login identity provider to use. The default value is blank, can be set to the 
identifier from a provider
 in the file specified in `nifi.login.identity.provider.configuration.file`. 
Setting this property will trigger NiFi to support username/password 
authentication.
 |`nifi.security.ocsp.responder.url`|This is the URL for the Online Certificate 
Status Protocol (OCSP) responder if one is being used. It is blank by default.
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/diagnostics/bootstrap/tasks/NiFiPropertiesDiagnosticTask.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/diagnostics/bootstrap/tasks/NiFiPropertiesDiagnosticTask.java
index 0443cc0..22cbe44 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/diagnostics/bootstrap/tasks/NiFiPropertiesDiagnosticTask.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/diagnostics/bootstrap/tasks/NiFiPropertiesDiagnosticTask.java
@@ -35,6 +35,7 @@ public class NiFiPropertiesDiagnosticTask implements 
DiagnosticTask {
         "nifi.ui.autorefresh.interval",
         "nifi.cluster.node.protocol.max.threads",
         "nifi.cluster.node.protocol.threads",
+        "nifi.security.allow.anonymous.authentication",
         "nifi.security.user.login.identity.provider",
         "nifi.security.user.authorizer",
         "nifi.provenance.repository.implementation",
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
index 702ffe8..58b250c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
@@ -155,6 +155,7 @@
         <nifi.security.truststoreType />
         <nifi.security.truststorePasswd />
         
<nifi.security.user.authorizer>managed-authorizer</nifi.security.user.authorizer>
+        
<nifi.security.allow.anonymous.authentication>false</nifi.security.allow.anonymous.authentication>
         <nifi.security.user.login.identity.provider />
         <nifi.security.x509.principal.extractor />
         <nifi.security.ocsp.responder.url />
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
index 2d55730..82174eb 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
@@ -170,6 +170,7 @@ nifi.security.truststore=${nifi.security.truststore}
 nifi.security.truststoreType=${nifi.security.truststoreType}
 nifi.security.truststorePasswd=${nifi.security.truststorePasswd}
 nifi.security.user.authorizer=${nifi.security.user.authorizer}
+nifi.security.allow.anonymous.authentication=${nifi.security.allow.anonymous.authentication}
 
nifi.security.user.login.identity.provider=${nifi.security.user.login.identity.provider}
 nifi.security.ocsp.responder.url=${nifi.security.ocsp.responder.url}
 
nifi.security.ocsp.responder.certificate=${nifi.security.ocsp.responder.certificate}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
index 647e6c8..b8d35e9 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiSecurityConfiguration.java
@@ -17,7 +17,8 @@
 package org.apache.nifi.web;
 
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.security.anonymous.NiFiAnonymousUserFilter;
+import 
org.apache.nifi.web.security.anonymous.NiFiAnonymousAuthenticationFilter;
+import 
org.apache.nifi.web.security.anonymous.NiFiAnonymousAuthenticationProvider;
 import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
 import org.apache.nifi.web.security.jwt.JwtAuthenticationProvider;
 import org.apache.nifi.web.security.knox.KnoxAuthenticationFilter;
@@ -76,7 +77,8 @@ public class NiFiWebApiSecurityConfiguration extends 
WebSecurityConfigurerAdapte
     private KnoxAuthenticationFilter knoxAuthenticationFilter;
     private KnoxAuthenticationProvider knoxAuthenticationProvider;
 
-    private NiFiAnonymousUserFilter anonymousAuthenticationFilter;
+    private NiFiAnonymousAuthenticationFilter anonymousAuthenticationFilter;
+    private NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider;
 
     public NiFiWebApiSecurityConfiguration() {
         super(true); // disable defaults
@@ -118,7 +120,10 @@ public class NiFiWebApiSecurityConfiguration extends 
WebSecurityConfigurerAdapte
         http.addFilterBefore(knoxFilterBean(), 
AnonymousAuthenticationFilter.class);
 
         // anonymous
-        http.anonymous().authenticationFilter(anonymousFilterBean());
+        http.addFilterAfter(anonymousFilterBean(), 
AnonymousAuthenticationFilter.class);
+
+        // disable default anonymous handling because it doesn't handle 
conditional authentication well
+        http.anonymous().disable();
     }
 
 
@@ -144,7 +149,8 @@ public class NiFiWebApiSecurityConfiguration extends 
WebSecurityConfigurerAdapte
                 .authenticationProvider(x509AuthenticationProvider)
                 .authenticationProvider(jwtAuthenticationProvider)
                 .authenticationProvider(otpAuthenticationProvider)
-                .authenticationProvider(knoxAuthenticationProvider);
+                .authenticationProvider(knoxAuthenticationProvider)
+                .authenticationProvider(anonymousAuthenticationProvider);
     }
 
     @Bean
@@ -190,9 +196,11 @@ public class NiFiWebApiSecurityConfiguration extends 
WebSecurityConfigurerAdapte
     }
 
     @Bean
-    public NiFiAnonymousUserFilter anonymousFilterBean() throws Exception {
+    public NiFiAnonymousAuthenticationFilter anonymousFilterBean() throws 
Exception {
         if (anonymousAuthenticationFilter == null) {
-            anonymousAuthenticationFilter = new NiFiAnonymousUserFilter();
+            anonymousAuthenticationFilter = new 
NiFiAnonymousAuthenticationFilter();
+            anonymousAuthenticationFilter.setProperties(properties);
+            
anonymousAuthenticationFilter.setAuthenticationManager(authenticationManager());
         }
         return anonymousAuthenticationFilter;
     }
@@ -218,6 +226,11 @@ public class NiFiWebApiSecurityConfiguration extends 
WebSecurityConfigurerAdapte
     }
 
     @Autowired
+    public void 
setAnonymousAuthenticationProvider(NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider) {
+        this.anonymousAuthenticationProvider = anonymousAuthenticationProvider;
+    }
+
+    @Autowired
     public void setX509AuthenticationProvider(X509AuthenticationProvider 
x509AuthenticationProvider) {
         this.x509AuthenticationProvider = x509AuthenticationProvider;
     }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
index 2571866..b56f708 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
@@ -28,6 +28,7 @@ import org.apache.nifi.nar.NarUnpacker;
 import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
 import org.apache.nifi.nar.SystemBundle;
 import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.util.StringUtils;
 
 import javax.ws.rs.core.Response;
 import java.io.File;
@@ -52,6 +53,7 @@ public class AccessControlHelper {
     private NiFiTestUser noneUser;
     private NiFiTestUser privilegedUser;
     private NiFiTestUser executeCodeUser;
+    private NiFiTestUser anonymousUser;
 
     private static final String CONTEXT_PATH = "/nifi-api";
 
@@ -67,7 +69,8 @@ public class AccessControlHelper {
         // configure the location of the nifi properties
         File nifiPropertiesFile = new File(nifiPropertiesPath);
         System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, 
nifiPropertiesFile.getAbsolutePath());
-        NiFiProperties props = NiFiProperties.createBasicNiFiProperties(null, 
null);
+
+        NiFiProperties props = 
NiFiProperties.createBasicNiFiProperties(nifiPropertiesPath, null);
         flowXmlPath = 
props.getProperty(NiFiProperties.FLOW_CONFIGURATION_FILE);
 
         final File libTargetDir = new 
File("target/test-classes/access-control/lib");
@@ -103,6 +106,7 @@ public class AccessControlHelper {
         noneUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.NONE_USER_DN);
         privilegedUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.PRIVILEGED_USER_DN);
         executeCodeUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.EXECUTED_CODE_USER_DN);
+        anonymousUser = new NiFiTestUser(server.getClient(), 
StringUtils.EMPTY);
 
         // populate the initial data flow
         NiFiWebApiTest.populateFlow(server.getClient(), baseUrl, 
readWriteUser, READ_WRITE_CLIENT_ID);
@@ -132,6 +136,10 @@ public class AccessControlHelper {
         return executeCodeUser;
     }
 
+    public NiFiTestUser getAnonymousUser() {
+        return anonymousUser;
+    }
+
     public void testGenericGetUri(final String uri) throws Exception {
         Response response;
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITAccessTokenEndpoint.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITAccessTokenEndpoint.java
index 0dc359f..5904929 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITAccessTokenEndpoint.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITAccessTokenEndpoint.java
@@ -16,21 +16,8 @@
  */
 package org.apache.nifi.integration.accesscontrol;
 
-import org.apache.nifi.web.security.jwt.JwtServiceTest;
 import net.minidev.json.JSONObject;
-import org.apache.commons.io.FileUtils;
-import org.apache.nifi.bundle.Bundle;
-import org.apache.nifi.integration.util.NiFiTestServer;
-import org.apache.nifi.integration.util.NiFiTestUser;
 import org.apache.nifi.integration.util.SourceTestProcessor;
-import org.apache.nifi.nar.ExtensionDiscoveringManager;
-import org.apache.nifi.nar.ExtensionManagerHolder;
-import org.apache.nifi.nar.NarClassLoadersHolder;
-import org.apache.nifi.nar.NarUnpacker;
-import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
-import org.apache.nifi.nar.SystemBundle;
-import org.apache.nifi.security.util.SslContextFactory;
-import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.dto.AccessConfigurationDTO;
 import org.apache.nifi.web.api.dto.AccessStatusDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
@@ -38,18 +25,13 @@ import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.AccessConfigurationEntity;
 import org.apache.nifi.web.api.entity.AccessStatusEntity;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
-import org.apache.nifi.web.util.WebUtils;
+import org.apache.nifi.web.security.jwt.JwtServiceTest;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import javax.net.ssl.SSLContext;
-import javax.ws.rs.client.Client;
 import javax.ws.rs.core.Response;
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -61,63 +43,15 @@ import java.util.StringJoiner;
  */
 public class ITAccessTokenEndpoint {
 
+    private static OneWaySslAccessControlHelper helper;
+
     private final String user = "unregistered-user@nifi";
     private final String password = "password";
     private static final String CLIENT_ID = "token-endpoint-id";
-    private static final String CONTEXT_PATH = "/nifi-api";
-
-    private static String flowXmlPath;
-    private static NiFiTestServer SERVER;
-    private static NiFiTestUser TOKEN_USER;
-    private static String BASE_URL;
 
     @BeforeClass
     public static void setup() throws Exception {
-        // configure the location of the nifi properties
-        File nifiPropertiesFile = new 
File("src/test/resources/access-control/nifi.properties");
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, 
nifiPropertiesFile.getAbsolutePath());
-
-        NiFiProperties props = NiFiProperties.createBasicNiFiProperties(null, 
null);
-        flowXmlPath = 
props.getProperty(NiFiProperties.FLOW_CONFIGURATION_FILE);
-
-        // delete the database directory to avoid issues with re-registration 
in testRequestAccessUsingToken
-        FileUtils.deleteDirectory(props.getDatabaseRepositoryPath().toFile());
-
-        final File libTargetDir = new 
File("target/test-classes/access-control/lib");
-        libTargetDir.mkdirs();
-
-        final File libSourceDir = new File("src/test/resources/lib");
-        for (final File libFile : libSourceDir.listFiles()) {
-            final File libDestFile = new File(libTargetDir, libFile.getName());
-            Files.copy(libFile.toPath(), libDestFile.toPath(), 
StandardCopyOption.REPLACE_EXISTING);
-        }
-
-        final Bundle systemBundle = SystemBundle.create(props);
-        NarUnpacker.unpackNars(props, systemBundle);
-        
NarClassLoadersHolder.getInstance().init(props.getFrameworkWorkingDirectory(), 
props.getExtensionsWorkingDirectory());
-
-        // load extensions
-        final ExtensionDiscoveringManager extensionManager = new 
StandardExtensionDiscoveringManager();
-        extensionManager.discoverExtensions(systemBundle, 
NarClassLoadersHolder.getInstance().getBundles());
-        ExtensionManagerHolder.init(extensionManager);
-
-        // start the server
-        SERVER = new NiFiTestServer("src/main/webapp", CONTEXT_PATH, props);
-        SERVER.startServer();
-        SERVER.loadFlow();
-
-        // get the base url
-        BASE_URL = SERVER.getBaseUrl() + CONTEXT_PATH;
-
-        // create the user
-        final Client client = WebUtils.createClient(null, 
createTrustContext(props));
-        TOKEN_USER = new NiFiTestUser(client, null);
-    }
-
-    private static SSLContext createTrustContext(final NiFiProperties props) 
throws Exception {
-        return 
SslContextFactory.createTrustSslContext(props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE),
-                
props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD).toCharArray(),
-                props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE), 
"TLS");
+        helper = new OneWaySslAccessControlHelper();
     }
 
     // -----------
@@ -130,9 +64,9 @@ public class ITAccessTokenEndpoint {
      */
     @Test
     public void testGetAccessConfig() throws Exception {
-        String url = BASE_URL + "/access/config";
+        String url = helper.getBaseUrl() + "/access/config";
 
-        Response response = TOKEN_USER.testGet(url);
+        Response response = helper.getUser().testGet(url);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -157,9 +91,9 @@ public class ITAccessTokenEndpoint {
      */
     @Test
     public void testCreateProcessorUsingToken() throws Exception {
-        String url = BASE_URL + "/access/token";
+        String url = helper.getBaseUrl() + "/access/token";
 
-        Response response = TOKEN_USER.testCreateToken(url, "user@nifi", 
"whatever");
+        Response response = helper.getUser().testCreateToken(url, "user@nifi", 
"whatever");
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -172,7 +106,7 @@ public class ITAccessTokenEndpoint {
     }
 
     private ProcessorDTO createProcessor(final String token) throws Exception {
-        String url = BASE_URL + "/process-groups/root/processors";
+        String url = helper.getBaseUrl() + "/process-groups/root/processors";
 
         // authorization header
         Map<String, String> headers = new HashMap<>();
@@ -194,7 +128,7 @@ public class ITAccessTokenEndpoint {
         entity.setComponent(processor);
 
         // perform the request
-        Response response = TOKEN_USER.testPostWithHeaders(url, entity, 
headers);
+        Response response = helper.getUser().testPostWithHeaders(url, entity, 
headers);
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -217,9 +151,9 @@ public class ITAccessTokenEndpoint {
      */
     @Test
     public void testInvalidCredentials() throws Exception {
-        String url = BASE_URL + "/access/token";
+        String url = helper.getBaseUrl() + "/access/token";
 
-        Response response = TOKEN_USER.testCreateToken(url, "user@nifi", "not 
a real password");
+        Response response = helper.getUser().testCreateToken(url, "user@nifi", 
"not a real password");
 
         // ensure the request is successful
         Assert.assertEquals(400, response.getStatus());
@@ -232,9 +166,9 @@ public class ITAccessTokenEndpoint {
      */
     @Test
     public void testUnknownUser() throws Exception {
-        String url = BASE_URL + "/access/token";
+        String url = helper.getBaseUrl() + "/access/token";
 
-        Response response = TOKEN_USER.testCreateToken(url, "not a real user", 
"not a real password");
+        Response response = helper.getUser().testCreateToken(url, "not a real 
user", "not a real password");
 
         // ensure the request is successful
         Assert.assertEquals(400, response.getStatus());
@@ -247,10 +181,10 @@ public class ITAccessTokenEndpoint {
      */
     @Test
     public void testRequestAccessUsingToken() throws Exception {
-        String accessStatusUrl = BASE_URL + "/access";
-        String accessTokenUrl = BASE_URL + "/access/token";
+        String accessStatusUrl = helper.getBaseUrl() + "/access";
+        String accessTokenUrl = helper.getBaseUrl() + "/access/token";
 
-        Response response = TOKEN_USER.testGet(accessStatusUrl);
+        Response response = helper.getUser().testGet(accessStatusUrl);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -261,7 +195,7 @@ public class ITAccessTokenEndpoint {
         // verify unknown
         Assert.assertEquals("UNKNOWN", accessStatus.getStatus());
 
-        response = TOKEN_USER.testCreateToken(accessTokenUrl, user, password);
+        response = helper.getUser().testCreateToken(accessTokenUrl, user, 
password);
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -274,7 +208,7 @@ public class ITAccessTokenEndpoint {
         headers.put("Authorization", "Bearer " + token);
 
         // check the status with the token
-        response = TOKEN_USER.testGetWithHeaders(accessStatusUrl, null, 
headers);
+        response = helper.getUser().testGetWithHeaders(accessStatusUrl, null, 
headers);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -288,11 +222,11 @@ public class ITAccessTokenEndpoint {
 
     @Test
     public void testLogOutSuccess() throws Exception {
-        String accessStatusUrl = BASE_URL + "/access";
-        String accessTokenUrl = BASE_URL + "/access/token";
-        String logoutUrl = BASE_URL + "/access/logout";
+        String accessStatusUrl = helper.getBaseUrl() + "/access";
+        String accessTokenUrl = helper.getBaseUrl() + "/access/token";
+        String logoutUrl = helper.getBaseUrl() + "/access/logout";
 
-        Response response = TOKEN_USER.testGet(accessStatusUrl);
+        Response response = helper.getUser().testGet(accessStatusUrl);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -303,7 +237,7 @@ public class ITAccessTokenEndpoint {
         // verify unknown
         Assert.assertEquals("UNKNOWN", accessStatus.getStatus());
 
-        response = TOKEN_USER.testCreateToken(accessTokenUrl, user, password);
+        response = helper.getUser().testCreateToken(accessTokenUrl, user, 
password);
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -316,7 +250,7 @@ public class ITAccessTokenEndpoint {
         headers.put("Authorization", "Bearer " + token);
 
         // check the status with the token
-        response = TOKEN_USER.testGetWithHeaders(accessStatusUrl, null, 
headers);
+        response = helper.getUser().testGetWithHeaders(accessStatusUrl, null, 
headers);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -329,21 +263,21 @@ public class ITAccessTokenEndpoint {
 
 
         // log out
-        response = TOKEN_USER.testGetWithHeaders(logoutUrl, null, headers);
+        response = helper.getUser().testDeleteWithHeaders(logoutUrl, headers);
         Assert.assertEquals(200, response.getStatus());
 
         // ensure we can no longer use our token
-        response = TOKEN_USER.testGetWithHeaders(accessStatusUrl, null, 
headers);
+        response = helper.getUser().testGetWithHeaders(accessStatusUrl, null, 
headers);
         Assert.assertEquals(401, response.getStatus());
     }
 
     @Test
     public void testLogOutNoTokenHeader() throws Exception {
-        String accessStatusUrl = BASE_URL + "/access";
-        String accessTokenUrl = BASE_URL + "/access/token";
-        String logoutUrl = BASE_URL + "/access/logout";
+        String accessStatusUrl = helper.getBaseUrl() + "/access";
+        String accessTokenUrl = helper.getBaseUrl() + "/access/token";
+        String logoutUrl = helper.getBaseUrl() + "/access/logout";
 
-        Response response = TOKEN_USER.testGet(accessStatusUrl);
+        Response response = helper.getUser().testGet(accessStatusUrl);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -354,7 +288,7 @@ public class ITAccessTokenEndpoint {
         // verify unknown
         Assert.assertEquals("UNKNOWN", accessStatus.getStatus());
 
-        response = TOKEN_USER.testCreateToken(accessTokenUrl, user, password);
+        response = helper.getUser().testCreateToken(accessTokenUrl, user, 
password);
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -367,7 +301,7 @@ public class ITAccessTokenEndpoint {
         headers.put("Authorization", "Bearer " + token);
 
         // check the status with the token
-        response = TOKEN_USER.testGetWithHeaders(accessStatusUrl, null, 
headers);
+        response = helper.getUser().testGetWithHeaders(accessStatusUrl, null, 
headers);
 
         // ensure the request is successful
         Assert.assertEquals(200, response.getStatus());
@@ -380,8 +314,8 @@ public class ITAccessTokenEndpoint {
 
 
         // log out should fail as we provided no token for logout to use
-        response = TOKEN_USER.testGetWithHeaders(logoutUrl, null, null);
-        Assert.assertEquals(500, response.getStatus());
+        response = helper.getUser().testDeleteWithHeaders(logoutUrl, null);
+        Assert.assertEquals(401, response.getStatus());
     }
 
     @Test
@@ -405,11 +339,11 @@ public class ITAccessTokenEndpoint {
         claims.put("iat", TOKEN_ISSUED_AT);
         final String EXPECTED_PAYLOAD = new JSONObject(claims).toString();
 
-        String accessStatusUrl = BASE_URL + "/access";
-        String accessTokenUrl = BASE_URL + "/access/token";
-        String logoutUrl = BASE_URL + "/access/logout";
+        String accessStatusUrl = helper.getBaseUrl() + "/access";
+        String accessTokenUrl = helper.getBaseUrl() + "/access/token";
+        String logoutUrl = helper.getBaseUrl() + "/access/logout";
 
-        Response response = TOKEN_USER.testCreateToken(accessTokenUrl, user, 
password);
+        Response response = helper.getUser().testCreateToken(accessTokenUrl, 
user, password);
 
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
@@ -419,7 +353,7 @@ public class ITAccessTokenEndpoint {
         Map<String, String> headers = new HashMap<>();
         headers.put("Authorization", "Bearer " + token);
         // check the status with the token
-        response = TOKEN_USER.testGetWithHeaders(accessStatusUrl, null, 
headers);
+        response = helper.getUser().testGetWithHeaders(accessStatusUrl, null, 
headers);
         Assert.assertEquals(200, response.getStatus());
 
         // Generate a token that will not match signatures with the generated 
token.
@@ -428,7 +362,7 @@ public class ITAccessTokenEndpoint {
         badHeaders.put("Authorization", "Bearer " + UNKNOWN_USER_TOKEN);
 
         // Log out should fail as we provide a bad token to use, signatures 
will mismatch
-        response = TOKEN_USER.testGetWithHeaders(logoutUrl, null, badHeaders);
+        response = helper.getUser().testGetWithHeaders(logoutUrl, null, 
badHeaders);
         Assert.assertEquals(401, response.getStatus());
     }
 
@@ -442,10 +376,10 @@ public class ITAccessTokenEndpoint {
         final long TOKEN_ISSUED_AT = currentTime;
         final long TOKEN_EXPIRATION_SECONDS = currentTime + EXPIRATION_SECONDS;
 
-        String accessTokenUrl = BASE_URL + "/access/token";
-        String logoutUrl = BASE_URL + "/access/logout";
+        String accessTokenUrl = helper.getBaseUrl() + "/access/token";
+        String logoutUrl = helper.getBaseUrl() + "/access/logout";
 
-        Response response = TOKEN_USER.testCreateToken(accessTokenUrl, user, 
password);
+        Response response = helper.getUser().testCreateToken(accessTokenUrl, 
user, password);
         // ensure the request is successful
         Assert.assertEquals(201, response.getStatus());
         // replace the user in the token with an unknown user
@@ -477,20 +411,12 @@ public class ITAccessTokenEndpoint {
         badHeaders.put("Authorization", "Bearer " + splicedUserToken);
 
         // Log out should fail as we provide a bad token to use, signatures 
will mismatch
-        response = TOKEN_USER.testGetWithHeaders(logoutUrl, null, badHeaders);
+        response = helper.getUser().testGetWithHeaders(logoutUrl, null, 
badHeaders);
         Assert.assertEquals(401, response.getStatus());
     }
 
     @AfterClass
     public static void cleanup() throws Exception {
-        // shutdown the server
-        SERVER.shutdownServer();
-        SERVER = null;
-
-        // look for the flow.xml
-        File flow = new File(flowXmlPath);
-        if (flow.exists()) {
-            flow.delete();
-        }
+        helper.cleanup();
     }
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OneWaySslAccessControlHelper.java
similarity index 57%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OneWaySslAccessControlHelper.java
index 2571866..e5942e8 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OneWaySslAccessControlHelper.java
@@ -16,9 +16,8 @@
  */
 package org.apache.nifi.integration.accesscontrol;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.nifi.bundle.Bundle;
-import org.apache.nifi.integration.NiFiWebApiTest;
-import org.apache.nifi.integration.util.NiFiTestAuthorizer;
 import org.apache.nifi.integration.util.NiFiTestServer;
 import org.apache.nifi.integration.util.NiFiTestUser;
 import org.apache.nifi.nar.ExtensionDiscoveringManager;
@@ -27,31 +26,22 @@ import org.apache.nifi.nar.NarClassLoadersHolder;
 import org.apache.nifi.nar.NarUnpacker;
 import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
 import org.apache.nifi.nar.SystemBundle;
+import org.apache.nifi.security.util.SslContextFactory;
 import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.util.WebUtils;
 
-import javax.ws.rs.core.Response;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.Client;
 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 
-import static org.junit.Assert.assertEquals;
-
 /**
  * Access control test for the dfm user.
  */
-public class AccessControlHelper {
-
-    public static final String NONE_CLIENT_ID = "client-id";
-    public static final String READ_CLIENT_ID = "r-client-id";
-    public static final String WRITE_CLIENT_ID = "w-client-id";
-    public static final String READ_WRITE_CLIENT_ID = "rw-client-id";
+public class OneWaySslAccessControlHelper {
 
-    private NiFiTestUser readUser;
-    private NiFiTestUser writeUser;
-    private NiFiTestUser readWriteUser;
-    private NiFiTestUser noneUser;
-    private NiFiTestUser privilegedUser;
-    private NiFiTestUser executeCodeUser;
+    private NiFiTestUser user;
 
     private static final String CONTEXT_PATH = "/nifi-api";
 
@@ -59,17 +49,21 @@ public class AccessControlHelper {
     private String baseUrl;
     private String flowXmlPath;
 
-    public AccessControlHelper() throws Exception {
+    public OneWaySslAccessControlHelper() throws Exception {
         this("src/test/resources/access-control/nifi.properties");
     }
 
-    public AccessControlHelper(final String nifiPropertiesPath) throws 
Exception {
+    public OneWaySslAccessControlHelper(final String nifiPropertiesPath) 
throws Exception {
         // configure the location of the nifi properties
         File nifiPropertiesFile = new File(nifiPropertiesPath);
         System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, 
nifiPropertiesFile.getAbsolutePath());
-        NiFiProperties props = NiFiProperties.createBasicNiFiProperties(null, 
null);
+
+        NiFiProperties props = 
NiFiProperties.createBasicNiFiProperties(nifiPropertiesPath, null);
         flowXmlPath = 
props.getProperty(NiFiProperties.FLOW_CONFIGURATION_FILE);
 
+        // delete the database directory to avoid issues with re-registration 
in testRequestAccessUsingToken
+        FileUtils.deleteDirectory(props.getDatabaseRepositoryPath().toFile());
+
         final File libTargetDir = new 
File("target/test-classes/access-control/lib");
         libTargetDir.mkdirs();
 
@@ -96,66 +90,25 @@ public class AccessControlHelper {
         // get the base url
         baseUrl = server.getBaseUrl() + CONTEXT_PATH;
 
-        // create the users - user purposefully decoupled from clientId (same 
user different browsers tabs)
-        readUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.READ_USER_DN);
-        writeUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.WRITE_USER_DN);
-        readWriteUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.READ_WRITE_USER_DN);
-        noneUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.NONE_USER_DN);
-        privilegedUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.PRIVILEGED_USER_DN);
-        executeCodeUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.EXECUTED_CODE_USER_DN);
-
-        // populate the initial data flow
-        NiFiWebApiTest.populateFlow(server.getClient(), baseUrl, 
readWriteUser, READ_WRITE_CLIENT_ID);
-    }
-
-    public NiFiTestUser getReadUser() {
-        return readUser;
-    }
-
-    public NiFiTestUser getWriteUser() {
-        return writeUser;
+        // create the user
+        final Client client = WebUtils.createClient(null, 
createTrustContext(props));
+        user = new NiFiTestUser(client, null);
     }
 
-    public NiFiTestUser getReadWriteUser() {
-        return readWriteUser;
-    }
-
-    public NiFiTestUser getNoneUser() {
-        return noneUser;
-    }
-
-    public NiFiTestUser getPrivilegedUser() {
-        return privilegedUser;
-    }
-
-    public NiFiTestUser getExecuteCodeUser() {
-        return executeCodeUser;
-    }
-
-    public void testGenericGetUri(final String uri) throws Exception {
-        Response response;
-
-        // read
-        response = getReadUser().testGet(uri);
-        assertEquals(200, response.getStatus());
-
-        // read/write
-        response = getReadWriteUser().testGet(uri);
-        assertEquals(200, response.getStatus());
-
-        // write
-        response = getWriteUser().testGet(uri);
-        assertEquals(403, response.getStatus());
-
-        // none
-        response = getNoneUser().testGet(uri);
-        assertEquals(403, response.getStatus());
+    public NiFiTestUser getUser() {
+        return user;
     }
 
     public String getBaseUrl() {
         return baseUrl;
     }
 
+    private static SSLContext createTrustContext(final NiFiProperties props) 
throws Exception {
+        return 
SslContextFactory.createTrustSslContext(props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE),
+                
props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD).toCharArray(),
+                props.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE), 
"TLS");
+    }
+
     public void cleanup() throws Exception {
         // shutdown the server
         server.shutdownServer();
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/AbstractAnonymousUserTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/AbstractAnonymousUserTest.java
new file mode 100644
index 0000000..66a7fac
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/AbstractAnonymousUserTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.integration.accesscontrol.anonymous;
+
+import org.apache.nifi.integration.util.NiFiTestUser;
+import org.apache.nifi.integration.util.SourceTestProcessor;
+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 javax.ws.rs.core.Response;
+
+public abstract class AbstractAnonymousUserTest {
+
+    private static final String CLIENT_ID = "anonymous-client-id";
+
+    /**
+     * Attempt to create a processor anonymously.
+     *
+     * @throws Exception ex
+     */
+    protected Response testCreateProcessor(final String baseUrl, final 
NiFiTestUser niFiTestUser) throws Exception {
+        final String url = baseUrl + "/process-groups/root/processors";
+
+        // create the processor
+        final ProcessorDTO processor = new ProcessorDTO();
+        processor.setName("Copy");
+        processor.setType(SourceTestProcessor.class.getName());
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(CLIENT_ID);
+        revision.setVersion(0l);
+
+        // create the entity body
+        final ProcessorEntity entity = new ProcessorEntity();
+        entity.setRevision(revision);
+        entity.setComponent(processor);
+
+        // perform the request
+        return niFiTestUser.testPost(url, entity);
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowDirectAnonymousAccess.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowDirectAnonymousAccess.java
new file mode 100644
index 0000000..004388c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowDirectAnonymousAccess.java
@@ -0,0 +1,66 @@
+/*
+ * 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.integration.accesscontrol.anonymous;
+
+import org.apache.nifi.integration.accesscontrol.OneWaySslAccessControlHelper;
+import org.apache.nifi.web.api.dto.ProcessorDTO;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Integration test for allowing direct anonymous access.
+ */
+public class ITAllowDirectAnonymousAccess extends AbstractAnonymousUserTest {
+
+    private static OneWaySslAccessControlHelper helper;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        helper = new 
OneWaySslAccessControlHelper("src/test/resources/access-control/nifi-anonymous-allowed.properties");
+    }
+
+    /**
+     * Attempt to create a processor anonymously.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testDirectAnonymousAccess() throws Exception {
+        final Response response = 
super.testCreateProcessor(helper.getBaseUrl(), helper.getUser());
+
+        // ensure the request is successful
+        Assert.assertEquals(201, response.getStatus());
+
+        // get the entity body
+        final ProcessorEntity entity = 
response.readEntity(ProcessorEntity.class);
+
+        // verify creation
+        final ProcessorDTO processor = entity.getComponent();
+        Assert.assertEquals("Copy", processor.getName());
+        
Assert.assertEquals("org.apache.nifi.integration.util.SourceTestProcessor", 
processor.getType());
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        helper.cleanup();
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowProxiedAnonymousAccess.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowProxiedAnonymousAccess.java
new file mode 100644
index 0000000..25c34a1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITAllowProxiedAnonymousAccess.java
@@ -0,0 +1,66 @@
+/*
+ * 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.integration.accesscontrol.anonymous;
+
+import org.apache.nifi.integration.accesscontrol.AccessControlHelper;
+import org.apache.nifi.web.api.dto.ProcessorDTO;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Integration test for allowing proxied anonymous access.
+ */
+public class ITAllowProxiedAnonymousAccess extends AbstractAnonymousUserTest {
+
+    private static AccessControlHelper helper;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        helper = new 
AccessControlHelper("src/test/resources/access-control/nifi-anonymous-allowed.properties");
+    }
+
+    /**
+     * Attempt to create a processor anonymously.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testProxiedAnonymousAccess() throws Exception {
+        final Response response = 
super.testCreateProcessor(helper.getBaseUrl(), helper.getAnonymousUser());
+
+        // ensure the request is successful
+        Assert.assertEquals(201, response.getStatus());
+
+        // get the entity body
+        final ProcessorEntity entity = 
response.readEntity(ProcessorEntity.class);
+
+        // verify creation
+        final ProcessorDTO processor = entity.getComponent();
+        Assert.assertEquals("Copy", processor.getName());
+        
Assert.assertEquals("org.apache.nifi.integration.util.SourceTestProcessor", 
processor.getType());
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        helper.cleanup();
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventDirectAnonymousAccess.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventDirectAnonymousAccess.java
new file mode 100644
index 0000000..1ab4bfe
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventDirectAnonymousAccess.java
@@ -0,0 +1,56 @@
+/*
+ * 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.integration.accesscontrol.anonymous;
+
+import org.apache.nifi.integration.accesscontrol.OneWaySslAccessControlHelper;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Integration test for preventing direct anonymous access.
+ */
+public class ITPreventDirectAnonymousAccess extends AbstractAnonymousUserTest {
+
+    private static OneWaySslAccessControlHelper helper;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        helper = new OneWaySslAccessControlHelper();
+    }
+
+    /**
+     * Attempt to create a processor anonymously.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testDirectAnonymousAccess() throws Exception {
+        final Response response = 
super.testCreateProcessor(helper.getBaseUrl(), helper.getUser());
+
+        // ensure the request is not successful
+        Assert.assertEquals(401, response.getStatus());
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        helper.cleanup();
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventProxiedAnonymousAccess.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventProxiedAnonymousAccess.java
new file mode 100644
index 0000000..281b882
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/anonymous/ITPreventProxiedAnonymousAccess.java
@@ -0,0 +1,57 @@
+/*
+ * 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.integration.accesscontrol.anonymous;
+
+import org.apache.nifi.integration.accesscontrol.AccessControlHelper;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Integration test for preventing proxied anonymous access.
+ */
+public class ITPreventProxiedAnonymousAccess extends AbstractAnonymousUserTest 
{
+
+    private static AccessControlHelper helper;
+
+    @BeforeClass
+    public static void setup() throws Exception {
+        System.out.println(ITPreventProxiedAnonymousAccess.class.getName() + " 
setup()");
+        helper = new AccessControlHelper();
+    }
+
+    /**
+     * Attempt to create a processor anonymously.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testProxiedAnonymousAccess() throws Exception {
+        final Response response = 
super.testCreateProcessor(helper.getBaseUrl(), helper.getAnonymousUser());
+
+        // ensure the request is not successful
+        Assert.assertEquals(401, response.getStatus());
+    }
+
+    @AfterClass
+    public static void cleanup() throws Exception {
+        helper.cleanup();
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
index fc3ed79..3d56591 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
@@ -77,6 +77,11 @@ public class NiFiTestAuthorizer implements Authorizer {
             return AuthorizationResult.resourceNotFound();
         }
 
+        // allow the anonymous user
+        if (request.isAnonymous()) {
+            return AuthorizationResult.approved();
+        }
+
         // allow the token user
         if (TOKEN_USER.equals(request.getIdentity())) {
             return AuthorizationResult.approved();
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi-anonymous-allowed.properties
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi-anonymous-allowed.properties
new file mode 100644
index 0000000..8ac6b3a
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi-anonymous-allowed.properties
@@ -0,0 +1,139 @@
+# 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.
+
+# Core Properties #
+nifi.flow.configuration.file=target/test-classes/access-control/flow.xml.gz
+nifi.flow.configuration.archive.dir=target/archive
+nifi.flowcontroller.autoResumeState=true
+nifi.flowcontroller.graceful.shutdown.period=10 sec
+nifi.flowservice.writedelay.interval=2 sec
+
+nifi.authorizer.configuration.file=target/test-classes/access-control/authorizers.xml
+nifi.login.identity.provider.configuration.file=target/test-classes/access-control/login-identity-providers.xml
+nifi.templates.directory=target/test-classes/access-control/templates
+nifi.ui.banner.text=TEST BANNER
+nifi.ui.autorefresh.interval=30 sec
+nifi.nar.library.directory=target/test-classes/access-control/lib
+nifi.nar.working.directory=target/test-classes/access-control/nar
+
+nifi.state.management.configuration.file=target/test-classes/access-control/state-management.xml
+nifi.state.management.embedded.zookeeper.start=false
+nifi.state.management.embedded.zookeeper.properties=
+nifi.state.management.embedded.zookeeper.max.instances=3
+nifi.state.management.provider.local=local-provider
+nifi.state.management.provider.cluster=
+
+# H2 Settings
+nifi.database.directory=target/test-classes/database_repository
+nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
+
+# FlowFile Repository
+nifi.provenance.repository.implementation=org.apache.nifi.provenance.VolatileProvenanceRepository
+nifi.flowfile.repository.directory=target/test-classes/flowfile_repository
+nifi.flowfile.repository.partitions=256
+nifi.flowfile.repository.checkpoint.interval=2 mins
+nifi.queue.swap.threshold=20000
+nifi.swap.storage.directory=target/test-classes/flowfile_repository/swap
+nifi.swap.in.period=5 sec
+nifi.swap.in.threads=1
+nifi.swap.out.period=5 sec
+nifi.swap.out.threads=4
+
+# Content Repository
+nifi.content.claim.max.appendable.size=10 MB
+nifi.content.claim.max.flow.files=100
+nifi.content.repository.directory.default=target/test-classes/content_repository
+nifi.content.repository.archive.enabled=false
+
+# Provenance Repository Properties
+nifi.provenance.repository.directory.default=./target/provenance_repository
+nifi.provenance.repository.query.threads=2
+nifi.provenance.repository.max.storage.time=24 hours
+nifi.provenance.repository.max.storage.size=1 GB
+nifi.provenance.repository.rollover.time=30 secs
+nifi.provenance.repository.rollover.size=100 MB
+
+# Component Status Repository
+nifi.components.status.repository.implementation=org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
+nifi.components.status.repository.buffer.size=288
+nifi.components.status.snapshot.frequency=10 secs
+
+# Site to Site properties
+#For testing purposes. Default value should actually be empty!
+nifi.remote.input.host=
+nifi.remote.input.socket.port=
+nifi.remote.input.secure=false
+
+# web properties #
+nifi.web.war.directory=target/test-classes/lib
+nifi.web.http.host=
+nifi.web.http.port=
+nifi.web.https.host=
+nifi.web.https.port=8443
+nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
+
+# security properties #
+nifi.sensitive.props.key=REPLACE_ME
+nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
+nifi.sensitive.props.provider=BC
+
+nifi.security.keystore=target/test-classes/access-control/keystore.jks
+nifi.security.keystoreType=JKS
+nifi.security.keystorePasswd=passwordpassword
+nifi.security.keyPasswd=
+nifi.security.truststore=target/test-classes/access-control/truststore.jks
+nifi.security.truststoreType=JKS
+nifi.security.truststorePasswd=passwordpassword
+nifi.security.user.login.identity.provider=test-provider
+nifi.security.user.authorizer=test-provider
+nifi.security.allow.anonymous.authentication=true
+
+# cluster common properties (cluster manager and nodes must have same values) #
+nifi.cluster.protocol.heartbeat.interval=5 sec
+nifi.cluster.protocol.is.secure=false
+nifi.cluster.protocol.socket.timeout=30 sec
+nifi.cluster.protocol.connection.handshake.timeout=45 sec
+# if multicast is used, then nifi.cluster.protocol.multicast.xxx properties 
must be configured #
+nifi.cluster.protocol.use.multicast=false
+nifi.cluster.protocol.multicast.address=
+nifi.cluster.protocol.multicast.port=
+nifi.cluster.protocol.multicast.service.broadcast.delay=500 ms
+nifi.cluster.protocol.multicast.service.locator.attempts=3
+nifi.cluster.protocol.multicast.service.locator.attempts.delay=1 sec
+
+# cluster node properties (only configure for cluster nodes) #
+nifi.cluster.is.node=false
+nifi.cluster.node.address=
+nifi.cluster.node.protocol.port=
+nifi.cluster.node.protocol.threads=2
+# if multicast is not used, nifi.cluster.node.unicast.xxx must have same 
values as nifi.cluster.manager.xxx #
+nifi.cluster.node.unicast.manager.address=
+nifi.cluster.node.unicast.manager.protocol.port=
+nifi.cluster.node.unicast.manager.authority.provider.port=
+
+# cluster manager properties (only configure for cluster manager) #
+nifi.cluster.is.manager=false
+nifi.cluster.manager.address=
+nifi.cluster.manager.protocol.port=
+nifi.cluster.manager.authority.provider.port=
+nifi.cluster.manager.authority.provider.threads=10
+nifi.cluster.manager.node.firewall.file=
+nifi.cluster.manager.node.event.history.size=10
+nifi.cluster.manager.node.api.connection.timeout=30 sec
+nifi.cluster.manager.node.api.read.timeout=30 sec
+nifi.cluster.manager.node.api.request.threads=10
+nifi.cluster.manager.flow.retrieval.delay=5 sec
+nifi.cluster.manager.protocol.threads=10
+nifi.cluster.manager.safemode.duration=0 sec
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationFilter.java
similarity index 59%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationFilter.java
index da9c52e..2565a58 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationFilter.java
@@ -16,25 +16,24 @@
  */
 package org.apache.nifi.web.security.anonymous;
 
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.nifi.authorization.user.NiFiUserDetails;
-import org.apache.nifi.authorization.user.StandardNiFiUser;
-import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
+import org.apache.nifi.web.security.NiFiAuthenticationFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.core.Authentication;
-import 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
 
-public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
+import javax.servlet.http.HttpServletRequest;
 
-    private static final String ANONYMOUS_KEY = "anonymousNifiKey";
+/**
+ * Extracts an anonymous authentication request from a specified servlet 
request.
+ */
+public class NiFiAnonymousAuthenticationFilter extends 
NiFiAuthenticationFilter {
 
-    public NiFiAnonymousUserFilter() {
-        super(ANONYMOUS_KEY);
-    }
+    private static final Logger logger = 
LoggerFactory.getLogger(NiFiAnonymousAuthenticationFilter.class);
 
     @Override
-    protected Authentication createAuthentication(HttpServletRequest request) {
-        return new NiFiAuthenticationToken(new 
NiFiUserDetails(StandardNiFiUser.ANONYMOUS));
+    public Authentication attemptAuthentication(final HttpServletRequest 
request) {
+        // return the anonymous authentication request for this http request
+        return new NiFiAnonymousAuthenticationRequestToken(request.isSecure(), 
request.getRemoteAddr());
     }
 
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProvider.java
new file mode 100644
index 0000000..7e107d0
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.anonymous;
+
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.security.InvalidAuthenticationException;
+import org.apache.nifi.web.security.NiFiAuthenticationProvider;
+import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ *
+ */
+public class NiFiAnonymousAuthenticationProvider extends 
NiFiAuthenticationProvider {
+
+    final NiFiProperties properties;
+
+    public NiFiAnonymousAuthenticationProvider(NiFiProperties nifiProperties, 
Authorizer authorizer) {
+        super(nifiProperties, authorizer);
+        this.properties = nifiProperties;
+    }
+
+    @Override
+    public Authentication authenticate(Authentication authentication) throws 
AuthenticationException {
+        final NiFiAnonymousAuthenticationRequestToken request = 
(NiFiAnonymousAuthenticationRequestToken) authentication;
+
+        if (request.isSecureRequest() && 
!properties.isAnonymousAuthenticationAllowed()) {
+            throw new InvalidAuthenticationException("Anonymous authentication 
has not been configured.");
+        }
+
+        return new NiFiAuthenticationToken(new 
NiFiUserDetails(StandardNiFiUser.populateAnonymousUser(null, 
request.getClientAddress())));
+    }
+
+    @Override
+    public boolean supports(Class<?> authentication) {
+        return 
NiFiAnonymousAuthenticationRequestToken.class.isAssignableFrom(authentication);
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationRequestToken.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationRequestToken.java
new file mode 100644
index 0000000..c0f0c93
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationRequestToken.java
@@ -0,0 +1,60 @@
+/*
+ * 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.anonymous;
+
+import org.apache.nifi.web.security.NiFiAuthenticationRequestToken;
+
+import static 
org.apache.nifi.authorization.user.StandardNiFiUser.ANONYMOUS_IDENTITY;
+
+/**
+ * This is an authentication request for an anonymous user.
+ */
+public class NiFiAnonymousAuthenticationRequestToken extends 
NiFiAuthenticationRequestToken {
+
+    final boolean secureRequest;
+
+    /**
+     * Creates a representation of the anonymous authentication request for a 
user.
+     *
+     * @param clientAddress the address of the client making the request
+     */
+    public NiFiAnonymousAuthenticationRequestToken(final boolean 
secureRequest, final String clientAddress) {
+        super(clientAddress);
+        setAuthenticated(false);
+        this.secureRequest = secureRequest;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return null;
+    }
+
+    public boolean isSecureRequest() {
+        return secureRequest;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return ANONYMOUS_IDENTITY;
+    }
+
+    @Override
+    public String toString() {
+        return "<anonymous>";
+    }
+
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
index 564171f..a56f9dd 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
@@ -64,11 +64,13 @@ public class X509AuthenticationProvider extends 
NiFiAuthenticationProvider {
 
     private X509IdentityProvider certificateIdentityProvider;
     private Authorizer authorizer;
+    final NiFiProperties properties;
 
     public X509AuthenticationProvider(final X509IdentityProvider 
certificateIdentityProvider, final Authorizer authorizer, final NiFiProperties 
nifiProperties) {
         super(nifiProperties, authorizer);
         this.certificateIdentityProvider = certificateIdentityProvider;
         this.authorizer = authorizer;
+        this.properties = nifiProperties;
     }
 
     @Override
@@ -99,6 +101,11 @@ public class X509AuthenticationProvider extends 
NiFiAuthenticationProvider {
                 // determine if the user is anonymous
                 final boolean isAnonymous = StringUtils.isBlank(identity);
                 if (isAnonymous) {
+                    // prevent anonymous users unless it's been explicitly 
configured
+                    if (!properties.isAnonymousAuthenticationAllowed()) {
+                        throw new InvalidAuthenticationException("Anonymous 
authentication has not been configured.");
+                    }
+
                     identity = StandardNiFiUser.ANONYMOUS_IDENTITY;
                 } else {
                     identity = mapIdentity(identity);
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
index 32c20c8..d37062a 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
@@ -100,4 +100,10 @@
         <constructor-arg ref="oidcProvider"/>
     </bean>
 
+    <!-- anonymous -->
+    <bean id="anonymousAuthenticationProvider" 
class="org.apache.nifi.web.security.anonymous.NiFiAnonymousAuthenticationProvider">
+        <constructor-arg ref="nifiProperties" index="0"/>
+        <constructor-arg ref="authorizer" index="1"/>
+    </bean>
+
 </beans>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProviderTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProviderTest.java
new file mode 100644
index 0000000..2422e8c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousAuthenticationProviderTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.anonymous;
+
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.util.StringUtils;
+import org.apache.nifi.web.security.InvalidAuthenticationException;
+import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class NiFiAnonymousAuthenticationProviderTest {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(NiFiAnonymousAuthenticationProviderTest.class);
+
+    @Test
+    public void testAnonymousDisabledNotSecure() throws Exception {
+        final NiFiProperties nifiProperties = 
Mockito.mock(NiFiProperties.class);
+        
when(nifiProperties.isAnonymousAuthenticationAllowed()).thenReturn(false);
+
+        final NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider = new 
NiFiAnonymousAuthenticationProvider(nifiProperties, mock(Authorizer.class));
+
+        final NiFiAnonymousAuthenticationRequestToken authenticationRequest = 
new NiFiAnonymousAuthenticationRequestToken(false, StringUtils.EMPTY);
+
+        final NiFiAuthenticationToken authentication = 
(NiFiAuthenticationToken) 
anonymousAuthenticationProvider.authenticate(authenticationRequest);
+        final NiFiUserDetails userDetails = (NiFiUserDetails) 
authentication.getDetails();
+        assertTrue(userDetails.getNiFiUser().isAnonymous());
+    }
+
+    @Test
+    public void testAnonymousEnabledNotSecure() throws Exception {
+        final NiFiProperties nifiProperties = 
Mockito.mock(NiFiProperties.class);
+        
when(nifiProperties.isAnonymousAuthenticationAllowed()).thenReturn(true);
+
+        final NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider = new 
NiFiAnonymousAuthenticationProvider(nifiProperties, mock(Authorizer.class));
+
+        final NiFiAnonymousAuthenticationRequestToken authenticationRequest = 
new NiFiAnonymousAuthenticationRequestToken(false, StringUtils.EMPTY);
+
+        final NiFiAuthenticationToken authentication = 
(NiFiAuthenticationToken) 
anonymousAuthenticationProvider.authenticate(authenticationRequest);
+        final NiFiUserDetails userDetails = (NiFiUserDetails) 
authentication.getDetails();
+        assertTrue(userDetails.getNiFiUser().isAnonymous());
+    }
+
+    @Test(expected = InvalidAuthenticationException.class)
+    public void testAnonymousDisabledSecure() throws Exception {
+        final NiFiProperties nifiProperties = 
Mockito.mock(NiFiProperties.class);
+        
when(nifiProperties.isAnonymousAuthenticationAllowed()).thenReturn(false);
+
+        final NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider = new 
NiFiAnonymousAuthenticationProvider(nifiProperties, mock(Authorizer.class));
+
+        final NiFiAnonymousAuthenticationRequestToken authenticationRequest = 
new NiFiAnonymousAuthenticationRequestToken(true, StringUtils.EMPTY);
+
+        anonymousAuthenticationProvider.authenticate(authenticationRequest);
+    }
+
+    @Test
+    public void testAnonymousEnabledSecure() throws Exception {
+        final NiFiProperties nifiProperties = 
Mockito.mock(NiFiProperties.class);
+        
when(nifiProperties.isAnonymousAuthenticationAllowed()).thenReturn(true);
+
+        final NiFiAnonymousAuthenticationProvider 
anonymousAuthenticationProvider = new 
NiFiAnonymousAuthenticationProvider(nifiProperties, mock(Authorizer.class));
+
+        final NiFiAnonymousAuthenticationRequestToken authenticationRequest = 
new NiFiAnonymousAuthenticationRequestToken(true, StringUtils.EMPTY);
+
+        final NiFiAuthenticationToken authentication = 
(NiFiAuthenticationToken) 
anonymousAuthenticationProvider.authenticate(authenticationRequest);
+        final NiFiUserDetails userDetails = (NiFiUserDetails) 
authentication.getDetails();
+        assertTrue(userDetails.getNiFiUser().isAnonymous());
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/x509/X509AuthenticationProviderTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/x509/X509AuthenticationProviderTest.java
index d61b29d..fc4cf5f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/x509/X509AuthenticationProviderTest.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/x509/X509AuthenticationProviderTest.java
@@ -34,7 +34,9 @@ import org.junit.Test;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -132,6 +134,27 @@ public class X509AuthenticationProviderTest {
 
     @Test
     public void testAnonymousWithOneProxy() {
+        // override the setting to enable anonymous authentication
+        final Map<String, String> additionalProperties = new HashMap<String, 
String>() {{
+            put(NiFiProperties.SECURITY_ANONYMOUS_AUTHENTICATION, 
Boolean.TRUE.toString());
+        }};
+        final NiFiProperties properties = 
NiFiProperties.createBasicNiFiProperties(null, additionalProperties);
+        x509AuthenticationProvider = new 
X509AuthenticationProvider(certificateIdentityProvider, authorizer, properties);
+
+        final NiFiAuthenticationToken auth = (NiFiAuthenticationToken) 
x509AuthenticationProvider.authenticate(getX509Request(buildProxyChain(ANONYMOUS),
 PROXY_1));
+        final NiFiUser user = ((NiFiUserDetails) 
auth.getDetails()).getNiFiUser();
+
+        assertNotNull(user);
+        assertEquals(StandardNiFiUser.ANONYMOUS_IDENTITY, user.getIdentity());
+        assertTrue(user.isAnonymous());
+
+        assertNotNull(user.getChain());
+        assertEquals(PROXY_1, user.getChain().getIdentity());
+        assertFalse(user.getChain().isAnonymous());
+    }
+
+    @Test(expected = InvalidAuthenticationException.class)
+    public void 
testAnonymousWithOneProxyWhileAnonymousAuthenticationPrevented() {
         final NiFiAuthenticationToken auth = (NiFiAuthenticationToken) 
x509AuthenticationProvider.authenticate(getX509Request(buildProxyChain(ANONYMOUS),
 PROXY_1));
         final NiFiUser user = ((NiFiUserDetails) 
auth.getDetails()).getNiFiUser();
 
@@ -169,6 +192,31 @@ public class X509AuthenticationProviderTest {
 
     @Test
     public void testAnonymousProxyInChain() {
+        // override the setting to enable anonymous authentication
+        final Map<String, String> additionalProperties = new HashMap<String, 
String>() {{
+            put(NiFiProperties.SECURITY_ANONYMOUS_AUTHENTICATION, 
Boolean.TRUE.toString());
+        }};
+        final NiFiProperties properties = 
NiFiProperties.createBasicNiFiProperties(null, additionalProperties);
+        x509AuthenticationProvider = new 
X509AuthenticationProvider(certificateIdentityProvider, authorizer, properties);
+
+        final NiFiAuthenticationToken auth = (NiFiAuthenticationToken) 
x509AuthenticationProvider.authenticate(getX509Request(buildProxyChain(IDENTITY_1,
 ANONYMOUS), PROXY_1));
+        final NiFiUser user = ((NiFiUserDetails) 
auth.getDetails()).getNiFiUser();
+
+        assertNotNull(user);
+        assertEquals(IDENTITY_1, user.getIdentity());
+        assertFalse(user.isAnonymous());
+
+        assertNotNull(user.getChain());
+        assertEquals(StandardNiFiUser.ANONYMOUS_IDENTITY, 
user.getChain().getIdentity());
+        assertTrue(user.getChain().isAnonymous());
+
+        assertNotNull(user.getChain().getChain());
+        assertEquals(PROXY_1, user.getChain().getChain().getIdentity());
+        assertFalse(user.getChain().getChain().isAnonymous());
+    }
+
+    @Test(expected = InvalidAuthenticationException.class)
+    public void 
testAnonymousProxyInChainWhileAnonymousAuthenticationPrevented() {
         final NiFiAuthenticationToken auth = (NiFiAuthenticationToken) 
x509AuthenticationProvider.authenticate(getX509Request(buildProxyChain(IDENTITY_1,
 ANONYMOUS), PROXY_1));
         final NiFiUser user = ((NiFiUserDetails) 
auth.getDetails()).getNiFiUser();
 
@@ -274,4 +322,4 @@ public class X509AuthenticationProviderTest {
         return certificate;
     }
 
-}
\ No newline at end of file
+}

Reply via email to