mirror of https://github.com/apache/nifi.git
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 <thenatog@gmail.com> This closes #4099.
This commit is contained in:
parent
7784178abd
commit
e81960f8e8
|
@ -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";
|
||||
|
@ -919,10 +920,19 @@ public abstract class NiFiProperties {
|
|||
return !StringUtils.isBlank(getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -217,6 +225,11 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
this.knoxAuthenticationProvider = knoxAuthenticationProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setAnonymousAuthenticationProvider(NiFiAnonymousAuthenticationProvider anonymousAuthenticationProvider) {
|
||||
this.anonymousAuthenticationProvider = anonymousAuthenticationProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setX509AuthenticationProvider(X509AuthenticationProvider x509AuthenticationProvider) {
|
||||
this.x509AuthenticationProvider = x509AuthenticationProvider;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
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.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.util.WebUtils;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Access control test for the dfm user.
|
||||
*/
|
||||
public class OneWaySslAccessControlHelper {
|
||||
|
||||
private NiFiTestUser user;
|
||||
|
||||
private static final String CONTEXT_PATH = "/nifi-api";
|
||||
|
||||
private NiFiTestServer server;
|
||||
private String baseUrl;
|
||||
private String flowXmlPath;
|
||||
|
||||
public OneWaySslAccessControlHelper() throws Exception {
|
||||
this("src/test/resources/access-control/nifi.properties");
|
||||
}
|
||||
|
||||
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(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();
|
||||
|
||||
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
|
||||
baseUrl = server.getBaseUrl() + CONTEXT_PATH;
|
||||
|
||||
// create the user
|
||||
final Client client = WebUtils.createClient(null, createTrustContext(props));
|
||||
user = new NiFiTestUser(client, null);
|
||||
}
|
||||
|
||||
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();
|
||||
server = null;
|
||||
|
||||
// look for the flow.xml and toss it
|
||||
File flow = new File(flowXmlPath);
|
||||
if (flow.exists()) {
|
||||
flow.delete();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
|
@ -16,25 +16,24 @@
|
|||
*/
|
||||
package org.apache.nifi.web.security.anonymous;
|
||||
|
||||
import org.apache.nifi.web.security.NiFiAuthenticationFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
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.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
/**
|
||||
* Extracts an anonymous authentication request from a specified servlet request.
|
||||
*/
|
||||
public class NiFiAnonymousAuthenticationFilter extends NiFiAuthenticationFilter {
|
||||
|
||||
public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
|
||||
|
||||
private static final String ANONYMOUS_KEY = "anonymousNifiKey";
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue