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 <[email protected]>
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 <[email protected]>
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
+}