diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
index c7440e2696..9a310a2fcc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
@@ -361,10 +361,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
// grant access to the proxy resource
addAccessPolicy(authorizations, ResourceType.Proxy.getValue(), jaxbNodeUser.getIdentifier(), WRITE_CODE);
- //grant access to controller resource
- addAccessPolicy(authorizations, ResourceType.Controller.getValue(), jaxbNodeUser.getIdentifier(), READ_CODE);
- addAccessPolicy(authorizations, ResourceType.Controller.getValue(), jaxbNodeUser.getIdentifier(), WRITE_CODE);
-
// grant the user read/write access data of the root group
if (rootGroupId != null) {
addAccessPolicy(authorizations, ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, jaxbNodeUser.getIdentifier(), READ_CODE);
diff --git a/nifi-toolkit/nifi-toolkit-admin/pom.xml b/nifi-toolkit/nifi-toolkit-admin/pom.xml
index 37500c653d..795cb0530d 100644
--- a/nifi-toolkit/nifi-toolkit-admin/pom.xml
+++ b/nifi-toolkit/nifi-toolkit-admin/pom.xml
@@ -47,10 +47,37 @@ language governing permissions and limitations under the License. -->
org.apache.nifi
nifi-client-dto
${client.version}
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+ org.apache.nifi
+ nifi-web-security
+ ${client.version}
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+ javax.servlet
+ javax.servlet-api
org.apache.nifi
nifi-properties
+
+
+ ch.qos.logback
+ logback-classic
+
+
org.apache.nifi
@@ -65,6 +92,12 @@ language governing permissions and limitations under the License. -->
org.apache.nifi
nifi-security-utils
+
+
+ ch.qos.logback
+ logback-classic
+
+
org.codehaus.jackson
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/AbstractAdminTool.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/AbstractAdminTool.groovy
index aed30274ca..79c5ef1f2b 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/AbstractAdminTool.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/AbstractAdminTool.groovy
@@ -87,7 +87,7 @@ public abstract class AbstractAdminTool {
final String versionStr = AdminUtil.getNiFiVersion(nifiConfDir,nifiLibDir)
if(!StringUtils.isEmpty(versionStr)){
- Version version = new Version(versionStr,".")
+ Version version = new Version(versionStr.replace("-","."),".")
Version minVersion = new Version(supportedMinimumVersion,".")
Version.VERSION_COMPARATOR.compare(version,minVersion) >= 0
}else{
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtil.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtil.groovy
index d4e5ff60e4..011cb1aa20 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtil.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtil.groovy
@@ -27,6 +27,7 @@ import org.apache.nifi.web.api.dto.NodeDTO
import org.apache.nifi.web.api.dto.util.DateTimeAdapter
import org.apache.nifi.web.api.entity.ClusterEntity
import org.apache.nifi.web.api.entity.NodeEntity
+import org.apache.nifi.web.security.ProxiedEntitiesUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -85,7 +86,7 @@ public class NiFiClientUtil {
urlBuilder.toString()
}
- public static ClusterEntity getCluster(final Client client, NiFiProperties niFiProperties, List activeUrls){
+ public static ClusterEntity getCluster(final Client client, NiFiProperties niFiProperties, List activeUrls, final String proxyDN){
if(activeUrls.isEmpty()){
final String url = getUrl(niFiProperties,null)
@@ -98,15 +99,21 @@ public class NiFiClientUtil {
String url = activeUrl + GET_CLUSTER_ENDPOINT
final WebResource webResource = client.resource(url)
- final ClientResponse response = webResource.type("application/json").get(ClientResponse.class)
+ ClientResponse response
- Integer status = response.getStatus()
+ if(url.startsWith("https")) {
+ response = webResource.type("application/json").header(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, ProxiedEntitiesUtils.formatProxyDn(proxyDN)).get(ClientResponse.class)
+ }else{
+ response = webResource.type("application/json").get(ClientResponse.class)
+ }
+
+ Integer status = response.status
if (status != 200) {
if (status == 404) {
logger.warn("This node is not attached to a cluster. Please connect to a node that is attached to the cluster for information")
} else {
- logger.warn("Failed with HTTP error code: {}, message: {}", status, response.getStatusInfo().getReasonPhrase())
+ logger.warn("Failed with HTTP error code: {}, message: {}", status, response.getEntity(String.class))
}
} else if (status == 200) {
return response.getEntity(ClusterEntity.class)
@@ -122,9 +129,9 @@ public class NiFiClientUtil {
}
- public static List getActiveClusterUrls(final Client client, NiFiProperties niFiProperties){
+ public static List getActiveClusterUrls(final Client client, NiFiProperties niFiProperties, final String proxyDN){
- final ClusterEntity clusterEntity = getCluster(client, niFiProperties, Lists.newArrayList())
+ final ClusterEntity clusterEntity = getCluster(client, niFiProperties, Lists.newArrayList(),proxyDN)
final List activeNodes = clusterEntity.cluster.nodes.findAll{ it.status == "CONNECTED" }
final List activeUrls = Lists.newArrayList()
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerTool.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerTool.groovy
index 3a1c4dfc03..b39c93c7cf 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerTool.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerTool.groovy
@@ -35,6 +35,7 @@ import org.apache.nifi.util.StringUtils
import org.apache.nifi.web.api.dto.NodeDTO
import org.apache.nifi.web.api.entity.ClusterEntity
import org.apache.nifi.web.api.entity.NodeEntity
+import org.apache.nifi.web.security.ProxiedEntitiesUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -45,6 +46,7 @@ public class NodeManagerTool extends AbstractAdminTool {
private static final String DEFAULT_DESCRIPTION = "This tool is used to manage nodes within a cluster. Supported functionality will remove node from cluster. "
private static final String HELP_ARG = "help"
private static final String VERBOSE_ARG = "verbose"
+ private static final String PROXY_DN = "proxyDn"
private static final String BOOTSTRAP_CONF = "bootstrapConf"
private static final String NIFI_INSTALL_DIR = "nifiInstallDir"
private static final String CLUSTER_URLS = "clusterUrls"
@@ -75,6 +77,7 @@ public class NodeManagerTool extends AbstractAdminTool {
final Options options = new Options()
options.addOption(Option.builder("h").longOpt(HELP_ARG).desc("Print help info").build())
options.addOption(Option.builder("v").longOpt(VERBOSE_ARG).desc("Set mode to verbose (default is false)").build())
+ options.addOption(Option.builder("p").longOpt(PROXY_DN).hasArg().desc("User or Proxy DN that has permission to send a notification. User must have view and modify privileges to 'access the controller' in NiFi").build())
options.addOption(Option.builder("b").longOpt(BOOTSTRAP_CONF).hasArg().desc("Existing Bootstrap Configuration file").build())
options.addOption(Option.builder("d").longOpt(NIFI_INSTALL_DIR).hasArg().desc("NiFi Installation Directory").build())
options.addOption(Option.builder("o").longOpt(OPERATION).hasArg().desc("Operation to connect, disconnect or remove node from cluster").build())
@@ -89,7 +92,7 @@ public class NodeManagerTool extends AbstractAdminTool {
return nodeDTOs.find{ it.address == nodeHost }
}
- NodeEntity updateNode(final String url, final Client client, final NodeDTO nodeDTO, final STATUS nodeStatus){
+ NodeEntity updateNode(final String url, final Client client, final NodeDTO nodeDTO, final STATUS nodeStatus,final String proxyDN){
final WebResource webResource = client.resource(url)
nodeDTO.status = nodeStatus
String json = NiFiClientUtil.convertToJson(nodeDTO)
@@ -98,36 +101,47 @@ public class NodeManagerTool extends AbstractAdminTool {
logger.info("Sending node info for update: " + json)
}
- final ClientResponse response = webResource.type("application/json").put(ClientResponse.class,json)
+ ClientResponse response
- if(response.getStatus() != 200){
- throw new RuntimeException("Failed with HTTP error code: " + response.getStatus())
+ if(url.startsWith("https")) {
+ response = webResource.type("application/json").header(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, ProxiedEntitiesUtils.formatProxyDn(proxyDN)).put(ClientResponse.class, json)
+ }else{
+ response = webResource.type("application/json").put(ClientResponse.class, json)
+ }
+
+ if(response.status != 200){
+ throw new RuntimeException("Failed with HTTP error code " + response.status + " with reason: " +response.getEntity(String.class))
}else{
response.getEntity(NodeEntity.class)
}
}
- void deleteNode(final String url, final Client client){
+ void deleteNode(final String url, final Client client, final String proxyDN){
final WebResource webResource = client.resource(url)
if(isVerbose){
logger.info("Attempting to delete node" )
}
+ ClientResponse response
- final ClientResponse response = webResource.type("application/json").delete(ClientResponse.class)
+ if(url.startsWith("https")) {
+ response = webResource.type("application/json").header(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, ProxiedEntitiesUtils.formatProxyDn(proxyDN)).delete(ClientResponse.class)
+ }else{
+ response = webResource.type("application/json").delete(ClientResponse.class)
+ }
- if(response.getStatus() != 200){
- throw new RuntimeException("Failed with HTTP error code: " + response.getStatus())
+ if(response.status != 200){
+ throw new RuntimeException("Failed with HTTP error code " + response.status + " with reason: " +response.getEntity(String.class))
}
}
- void disconnectNode(final Client client, NiFiProperties niFiProperties, List activeUrls){
- final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls)
+ void disconnectNode(final Client client, NiFiProperties niFiProperties, List activeUrls, final String proxyDN){
+ final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls,proxyDN)
NodeDTO currentNode = getCurrentNode(clusterEntity,niFiProperties)
for(String activeUrl: activeUrls) {
try {
final String url = activeUrl + NODE_ENDPOINT + File.separator + currentNode.nodeId
- updateNode(url, client, currentNode, STATUS.DISCONNECTING)
+ updateNode(url, client, currentNode, STATUS.DISCONNECTING,proxyDN)
return
} catch (Exception ex){
logger.warn("Could not connect to node on "+activeUrl+". Exception: "+ex.toString())
@@ -136,13 +150,13 @@ public class NodeManagerTool extends AbstractAdminTool {
throw new RuntimeException("Could not successfully complete request")
}
- void connectNode(final Client client, NiFiProperties niFiProperties,List activeUrls){
- final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls)
+ void connectNode(final Client client, NiFiProperties niFiProperties,List activeUrls, final String proxyDN){
+ final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls,proxyDN)
NodeDTO currentNode = getCurrentNode(clusterEntity,niFiProperties)
for(String activeUrl: activeUrls) {
try {
final String url = activeUrl + NODE_ENDPOINT + File.separator + currentNode.nodeId
- updateNode(url, client, currentNode, STATUS.CONNECTING)
+ updateNode(url, client, currentNode, STATUS.CONNECTING,proxyDN)
return
} catch (Exception ex){
logger.warn("Could not connect to node on "+activeUrl+". Exception: "+ex.toString())
@@ -151,9 +165,9 @@ public class NodeManagerTool extends AbstractAdminTool {
throw new RuntimeException("Could not successfully complete request")
}
- void removeNode(final Client client, NiFiProperties niFiProperties, List activeUrls){
+ void removeNode(final Client client, NiFiProperties niFiProperties, List activeUrls, final String proxyDN){
- final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls)
+ final ClusterEntity clusterEntity = NiFiClientUtil.getCluster(client, niFiProperties, activeUrls,proxyDN)
NodeDTO currentNode = getCurrentNode(clusterEntity,niFiProperties)
if(currentNode != null) {
@@ -169,11 +183,11 @@ public class NodeManagerTool extends AbstractAdminTool {
}
if(currentNode.status == "CONNECTED") {
- currentNode = updateNode(url, client, currentNode, STATUS.DISCONNECTING).node
+ currentNode = updateNode(url, client, currentNode, STATUS.DISCONNECTING,proxyDN).node
}
if(currentNode.status == "DISCONNECTED") {
- deleteNode(url, client)
+ deleteNode(url, client,proxyDN)
}
if(isVerbose){
@@ -210,6 +224,7 @@ public class NodeManagerTool extends AbstractAdminTool {
}
final String bootstrapConfFileName = commandLine.getOptionValue(BOOTSTRAP_CONF)
+ final String proxyDN = commandLine.getOptionValue(PROXY_DN)
final File bootstrapConf = new File(bootstrapConfFileName)
Properties bootstrapProperties = getBootstrapConf(Paths.get(bootstrapConfFileName))
String nifiConfDir = getRelativeDirectory(bootstrapProperties.getProperty("conf.dir"), bootstrapConf.getCanonicalFile().getParentFile().getParentFile().getCanonicalPath())
@@ -218,6 +233,10 @@ public class NodeManagerTool extends AbstractAdminTool {
final String key = NiFiPropertiesLoader.extractKeyFromBootstrapFile(bootstrapConfFileName)
final NiFiProperties niFiProperties = NiFiPropertiesLoader.withKey(key).load(nifiPropertiesFileName)
+ if(!StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT)) && StringUtils.isEmpty(proxyDN)) {
+ throw new UnsupportedOperationException("Proxy DN is required for sending a notification to this node or cluster")
+ }
+
final String nifiInstallDir = commandLine.getOptionValue(NIFI_INSTALL_DIR)
if(supportedNiFiMinimumVersion(nifiConfDir,nifiLibDir,SUPPORTED_MINIMUM_VERSION) && NiFiClientUtil.isCluster(niFiProperties)){
@@ -235,7 +254,7 @@ public class NodeManagerTool extends AbstractAdminTool {
final String urlList = commandLine.getOptionValue(CLUSTER_URLS)
activeUrls = urlList.tokenize(',')
}else{
- activeUrls = NiFiClientUtil.getActiveClusterUrls(client,niFiProperties)
+ activeUrls = NiFiClientUtil.getActiveClusterUrls(client,niFiProperties,proxyDN)
}
if(isVerbose){
@@ -243,13 +262,13 @@ public class NodeManagerTool extends AbstractAdminTool {
}
if(operation.toLowerCase().equals(REMOVE)){
- removeNode(client,niFiProperties,activeUrls)
+ removeNode(client,niFiProperties,activeUrls,proxyDN)
}
else if(operation.toLowerCase().equals(DISCONNECT)){
- disconnectNode(client,niFiProperties,activeUrls)
+ disconnectNode(client,niFiProperties,activeUrls,proxyDN)
}
else if(operation.toLowerCase().equals(CONNECT)){
- connectNode(client,niFiProperties,activeUrls)
+ connectNode(client,niFiProperties,activeUrls,proxyDN)
}
else{
throw new ParseException("Invalid operation provided: " + operation)
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/notify/NotificationTool.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/notify/NotificationTool.groovy
index ce87499c8a..215aee839e 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/notify/NotificationTool.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/notify/NotificationTool.groovy
@@ -34,6 +34,7 @@ import org.apache.nifi.toolkit.admin.client.NiFiClientFactory
import org.apache.nifi.util.NiFiProperties
import org.apache.nifi.web.api.dto.BulletinDTO
import org.apache.nifi.web.api.entity.BulletinEntity
+import org.apache.nifi.web.security.ProxiedEntitiesUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -45,6 +46,7 @@ public class NotificationTool extends AbstractAdminTool {
private static final String HELP_ARG = "help"
private static final String VERBOSE_ARG = "verbose"
private static final String BOOTSTRAP_CONF = "bootstrapConf"
+ private static final String PROXY_DN = "proxyDn"
private static final String NIFI_INSTALL_DIR = "nifiInstallDir"
private static final String NOTIFICATION_MESSAGE = "message"
private static final String NOTIFICATION_LEVEL = "level"
@@ -70,6 +72,7 @@ public class NotificationTool extends AbstractAdminTool {
final Options options = new Options()
options.addOption(Option.builder("h").longOpt(HELP_ARG).desc("Print help info").build())
options.addOption(Option.builder("v").longOpt(VERBOSE_ARG).desc("Set mode to verbose (default is false)").build())
+ options.addOption(Option.builder("p").longOpt(PROXY_DN).hasArg().desc("User or Proxy DN that has permission to send a notification. User must have view and modify privileges to 'access the controller' in NiFi").build())
options.addOption(Option.builder("b").longOpt(BOOTSTRAP_CONF).hasArg().desc("Existing Bootstrap Configuration file").build())
options.addOption(Option.builder("d").longOpt(NIFI_INSTALL_DIR).hasArg().desc("NiFi Installation Directory").build())
options.addOption(Option.builder("m").longOpt(NOTIFICATION_MESSAGE).hasArg().desc("Notification message for nifi instance or cluster").build())
@@ -77,7 +80,7 @@ public class NotificationTool extends AbstractAdminTool {
options
}
- void notifyCluster(final ClientFactory clientFactory, final String nifiPropertiesFile, final String bootstrapConfFile, final String nifiInstallDir, final String message, final String level){
+ void notifyCluster(final ClientFactory clientFactory, final String nifiPropertiesFile, final String bootstrapConfFile, final String nifiInstallDir, final String message, final String level, final String proxyDN){
if(isVerbose){
logger.info("Loading nifi properties for host information")
@@ -99,7 +102,19 @@ public class NotificationTool extends AbstractAdminTool {
bulletinDTO.category = "NOTICE"
bulletinDTO.level = StringUtils.isEmpty(level) ? "INFO" : level
bulletinEntity.bulletin = bulletinDTO
- final ClientResponse response = webResource.type("application/json").post(ClientResponse.class, bulletinEntity)
+
+ ClientResponse response
+ if(!org.apache.nifi.util.StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT))) {
+
+ if(StringUtils.isEmpty(proxyDN)){
+ throw new UnsupportedOperationException("Proxy DN is required for sending a notification to this node or cluster")
+ }
+
+ response = webResource.type("application/json").header(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, ProxiedEntitiesUtils.formatProxyDn(proxyDN)).post(ClientResponse.class, bulletinEntity)
+ }
+ else {
+ response = webResource.type("application/json").post(ClientResponse.class, bulletinEntity)
+ }
Integer status = response.getStatus()
@@ -107,7 +122,7 @@ public class NotificationTool extends AbstractAdminTool {
if(status == 404){
throw new RuntimeException("The notification feature is not supported by each node in the cluster")
}else{
- throw new RuntimeException("Failed with HTTP error code: " + status)
+ throw new RuntimeException("Failed with HTTP error code " + status + " with reason: " +response.getEntity(String.class))
}
}
@@ -130,6 +145,7 @@ public class NotificationTool extends AbstractAdminTool {
final String bootstrapConfFileName = commandLine.getOptionValue(BOOTSTRAP_CONF)
final File bootstrapConf = new File(bootstrapConfFileName)
final Properties bootstrapProperties = getBootstrapConf(Paths.get(bootstrapConfFileName))
+ final String proxyDN = commandLine.getOptionValue(PROXY_DN)
final String parentPathName = bootstrapConf.getCanonicalFile().getParentFile().getParentFile().getCanonicalPath()
final String nifiConfDir = getRelativeDirectory(bootstrapProperties.getProperty("conf.dir"),parentPathName)
final String nifiLibDir = getRelativeDirectory(bootstrapProperties.getProperty("lib.dir"),parentPathName)
@@ -143,7 +159,7 @@ public class NotificationTool extends AbstractAdminTool {
logger.info("Attempting to connect with nifi using properties:", nifiPropertiesFileName)
}
- notifyCluster(clientFactory, nifiPropertiesFileName, bootstrapConfFileName,nifiInstallDir,notificationMessage,notificationLevel)
+ notifyCluster(clientFactory, nifiPropertiesFileName, bootstrapConfFileName,nifiInstallDir,notificationMessage,notificationLevel,proxyDN)
if(isVerbose) {
logger.info("Message sent successfully to NiFi.")
@@ -169,7 +185,7 @@ public class NotificationTool extends AbstractAdminTool {
try{
tool.parse(clientFactory,args)
- } catch (ParseException | UnsupportedOperationException e) {
+ } catch (ParseException | UnsupportedOperationException | RuntimeException e) {
tool.printUsage(e.message);
System.exit(1)
}
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/util/Version.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/util/Version.groovy
index db5dc04b19..33a11a7cb9 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/util/Version.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/util/Version.groovy
@@ -64,11 +64,17 @@ class Version {
String[] o2V = o2.versionNumber
for(int i = 0; i < o1V.length; i++) {
- Integer val1 = Integer.parseInt(o1V[i])
- Integer val2 = Integer.parseInt(o2V[i])
- if (val1.compareTo(val2) != 0) {
- return val1.compareTo(val2)
+
+ if(o2V.length == i ){
+ return 1
+ }else {
+ Integer val1 = Integer.parseInt(o1V[i])
+ Integer val2 = Integer.parseInt(o2V[i])
+ if (val1.compareTo(val2) != 0) {
+ return val1.compareTo(val2)
+ }
}
+
}
return 0
}
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy
index 32a1522739..0400efe919 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy
@@ -63,7 +63,7 @@ class NiFiClientUtilSpec extends Specification{
def ClusterEntity clusterEntity = Mock ClusterEntity
when:
- def entity = NiFiClientUtil.getCluster(client, niFiProperties, [])
+ def entity = NiFiClientUtil.getCluster(client, niFiProperties, [], null)
then:
@@ -77,6 +77,35 @@ class NiFiClientUtilSpec extends Specification{
}
+ def "get secured cluster info successfully"(){
+
+ given:
+ def Client client = Mock Client
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+
+ when:
+ def entity = NiFiClientUtil.getCluster(client, niFiProperties, [], "ydavis@nifi")
+
+ then:
+
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT) >> "8081"
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_HOST) >> "localhost"
+
+ 1 * client.resource(_ as String) >> resource
+ 1 * resource.type(_) >> builder
+ 1 * builder.header(_,_) >> builder
+ 1 * builder.get(_) >> response
+ 1 * response.getStatus() >> 200
+ 1 * response.getEntity(ClusterEntity.class) >> clusterEntity
+ entity == clusterEntity
+
+ }
+
+
def "get cluster info fails"(){
given:
@@ -89,7 +118,7 @@ class NiFiClientUtilSpec extends Specification{
when:
- NiFiClientUtil.getCluster(client, niFiProperties, [])
+ NiFiClientUtil.getCluster(client, niFiProperties, [],null)
then:
@@ -98,8 +127,7 @@ class NiFiClientUtilSpec extends Specification{
1 * resource.type(_) >> builder
1 * builder.get(_) >> response
1 * response.getStatus() >> 500
- 1 * response.getStatusInfo() >> statusType
- 1 * statusType.getReasonPhrase() >> "Only a node connected to a cluster can process the request."
+ 1 * response.getEntity(String.class) >> "Only a node connected to a cluster can process the request."
def e = thrown(RuntimeException)
e.message == "Unable to obtain cluster information"
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy
index e482bbc071..5fd7d3d4b1 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy
@@ -1,4 +1,3 @@
-
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -32,6 +31,8 @@ import org.junit.contrib.java.lang.system.ExpectedSystemExit
import org.junit.contrib.java.lang.system.SystemOutRule
import spock.lang.Specification
+import javax.ws.rs.core.Response
+
class NodeManagerToolSpec extends Specification{
@Rule
@@ -174,7 +175,7 @@ class NodeManagerToolSpec extends Specification{
def config = new NodeManagerTool()
when:
- config.deleteNode(url,client)
+ config.deleteNode(url,client,null)
then:
@@ -185,6 +186,30 @@ class NodeManagerToolSpec extends Specification{
}
+ def "delete secured node successfully"(){
+
+ given:
+ def String url = "https://locahost:8080/nifi-api/controller"
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def config = new NodeManagerTool()
+
+ when:
+ config.deleteNode(url,client,null)
+
+ then:
+
+ 1 * client.resource(_ as String) >> resource
+ 1 * resource.type(_) >> builder
+ 1 * builder.header(_,_) >> builder
+ 1 * builder.delete(_) >> response
+ 1 * response.getStatus() >> 200
+
+ }
+
+
def "delete node failed"(){
given:
@@ -193,18 +218,20 @@ class NodeManagerToolSpec extends Specification{
def WebResource resource = Mock WebResource
def WebResource.Builder builder = Mock WebResource.Builder
def ClientResponse response = Mock ClientResponse
+ def Response.StatusType statusType = Mock Response.StatusType
def config = new NodeManagerTool()
when:
- config.deleteNode(url,client)
+ config.deleteNode(url,client,null)
then:
1 * client.resource(_ as String) >> resource
1 * resource.type(_) >> builder
1 * builder.delete(_) >> response
2 * response.getStatus() >> 403
+ 1 * response.getEntity(String.class) >> "Unauthorized User"
def e = thrown(RuntimeException)
- e.message == "Failed with HTTP error code: 403"
+ e.message == "Failed with HTTP error code 403 with reason: Unauthorized User"
}
@@ -221,7 +248,7 @@ class NodeManagerToolSpec extends Specification{
def config = new NodeManagerTool()
when:
- def entity = config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING)
+ def entity = config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING,null)
then:
1 * client.resource(_ as String) >> resource
@@ -233,6 +260,32 @@ class NodeManagerToolSpec extends Specification{
}
+ def "update secured node successfully"(){
+
+ given:
+ def String url = "https://locahost:8080/nifi-api/controller"
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def NodeDTO nodeDTO = new NodeDTO()
+ def NodeEntity nodeEntity = Mock NodeEntity
+ def config = new NodeManagerTool()
+
+ when:
+ def entity = config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING,null)
+
+ then:
+ 1 * client.resource(_ as String) >> resource
+ 1 * resource.type(_) >> builder
+ 1 * builder.header(_,_) >> builder
+ 1 * builder.put(_,_) >> response
+ 1 * response.getStatus() >> 200
+ 1 * response.getEntity(NodeEntity.class) >> nodeEntity
+ entity == nodeEntity
+
+ }
+
def "update node fails"(){
given:
@@ -241,19 +294,21 @@ class NodeManagerToolSpec extends Specification{
def WebResource resource = Mock WebResource
def WebResource.Builder builder = Mock WebResource.Builder
def ClientResponse response = Mock ClientResponse
+ def Response.StatusType statusType = Mock Response.StatusType
def NodeDTO nodeDTO = new NodeDTO()
def config = new NodeManagerTool()
when:
- config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING)
+ config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING,null)
then:
1 * client.resource(_ as String) >> resource
1 * resource.type(_) >> builder
1 * builder.put(_,_) >> response
2 * response.getStatus() >> 403
+ 1 * response.getEntity(String.class) >> "Unauthorized User"
def e = thrown(RuntimeException)
- e.message == "Failed with HTTP error code: 403"
+ e.message == "Failed with HTTP error code 403 with reason: Unauthorized User"
}
@@ -290,10 +345,48 @@ class NodeManagerToolSpec extends Specification{
nodeDTO.address >> "localhost"
expect:
- config.disconnectNode(client, niFiProperties,["http://localhost:8080"])
+ config.disconnectNode(client, niFiProperties,["http://localhost:8080"],null)
}
+
+ def "disconnect secured node successfully"(){
+
+ setup:
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+ def ClusterDTO clusterDTO = Mock ClusterDTO
+ def NodeDTO nodeDTO = new NodeDTO()
+ nodeDTO.address = "localhost"
+ nodeDTO.nodeId = "1"
+ nodeDTO.status = "CONNECTED"
+ def List nodeDTOs = [nodeDTO]
+ def NodeEntity nodeEntity = new NodeEntity()
+ nodeEntity.node = nodeDTO
+ def config = new NodeManagerTool()
+
+
+ niFiProperties.getProperty(_) >> "localhost"
+ client.resource(_ as String) >> resource
+ resource.type(_) >> builder
+ builder.get(ClientResponse.class) >> response
+ builder.header(_,_) >> builder
+ builder.put(_,_) >> response
+ response.getStatus() >> 200
+ response.getEntity(ClusterEntity.class) >> clusterEntity
+ response.getEntity(NodeEntity.class) >> nodeEntity
+ clusterEntity.getCluster() >> clusterDTO
+ clusterDTO.getNodes() >> nodeDTOs
+ nodeDTO.address >> "localhost"
+
+ expect:
+ config.disconnectNode(client, niFiProperties,["https://localhost:8080"],null)
+
+ }
def "connect node successfully"(){
setup:
@@ -327,7 +420,7 @@ class NodeManagerToolSpec extends Specification{
nodeDTO.address >> "localhost"
expect:
- config.connectNode(client, niFiProperties,["http://localhost:8080"])
+ config.connectNode(client, niFiProperties,["http://localhost:8080"],null)
}
@@ -365,7 +458,7 @@ class NodeManagerToolSpec extends Specification{
nodeDTO.address >> "localhost"
expect:
- config.removeNode(client, niFiProperties,["http://localhost:8080"])
+ config.removeNode(client, niFiProperties,["http://localhost:8080"],null)
}
@@ -410,5 +503,172 @@ class NodeManagerToolSpec extends Specification{
}
+ def "parse args and fail connecting secured node"(){
+
+ setup:
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+ def ClusterDTO clusterDTO = Mock ClusterDTO
+ def NodeDTO nodeDTO = new NodeDTO()
+ nodeDTO.address = "localhost"
+ nodeDTO.nodeId = "1"
+ nodeDTO.status = "DISCONNECTED"
+ def List nodeDTOs = [nodeDTO]
+ def NodeEntity nodeEntity = new NodeEntity()
+ nodeEntity.node = nodeDTO
+ def config = new NodeManagerTool()
+
+
+ niFiProperties.getProperty(_) >> "localhost"
+ clientFactory.getClient(_,_) >> client
+ client.resource(_ as String) >> resource
+ resource.type(_) >> builder
+ builder.get(ClientResponse.class) >> response
+ builder.header(_,_) >> builder
+ builder.put(_,_) >> response
+ response.getStatus() >> 200
+ response.getEntity(ClusterEntity.class) >> clusterEntity
+ response.getEntity(NodeEntity.class) >> nodeEntity
+ clusterEntity.getCluster() >> clusterDTO
+ clusterDTO.getNodes() >> nodeDTOs
+ nodeDTO.address >> "localhost"
+
+ when:
+ config.parse(clientFactory,["-b","src/test/resources/notify/conf_secure/bootstrap.conf","-d","/bogus/nifi/dir","-o","connect","-u","https://localhost:8080,https://localhost1:8080"] as String[])
+
+ then:
+ def e = thrown(UnsupportedOperationException)
+ e.message == "Proxy DN is required for sending a notification to this node or cluster"
+
+
+ }
+
+ def "parse args and connect secured node"(){
+
+ setup:
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+ def ClusterDTO clusterDTO = Mock ClusterDTO
+ def NodeDTO nodeDTO = new NodeDTO()
+ nodeDTO.address = "localhost"
+ nodeDTO.nodeId = "1"
+ nodeDTO.status = "DISCONNECTED"
+ def List nodeDTOs = [nodeDTO]
+ def NodeEntity nodeEntity = new NodeEntity()
+ nodeEntity.node = nodeDTO
+ def config = new NodeManagerTool()
+
+
+ niFiProperties.getProperty(_) >> "localhost"
+ clientFactory.getClient(_,_) >> client
+ client.resource(_ as String) >> resource
+ resource.type(_) >> builder
+ builder.get(ClientResponse.class) >> response
+ builder.header(_,_) >> builder
+ builder.put(_,_) >> response
+ response.getStatus() >> 200
+ response.getEntity(ClusterEntity.class) >> clusterEntity
+ response.getEntity(NodeEntity.class) >> nodeEntity
+ clusterEntity.getCluster() >> clusterDTO
+ clusterDTO.getNodes() >> nodeDTOs
+ nodeDTO.address >> "localhost"
+
+ expect:
+ config.parse(clientFactory,["-b","src/test/resources/notify/conf_secure/bootstrap.conf","-d","/bogus/nifi/dir","-o","connect","-u","https://localhost:8080,https://localhost1:8080","-p","ydavis@nifi"] as String[])
+
+ }
+
+ def "parse args and disconnect secured node"(){
+
+ setup:
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+ def ClusterDTO clusterDTO = Mock ClusterDTO
+ def NodeDTO nodeDTO = new NodeDTO()
+ nodeDTO.address = "localhost"
+ nodeDTO.nodeId = "1"
+ nodeDTO.status = "CONNECTED"
+ def List nodeDTOs = [nodeDTO]
+ def NodeEntity nodeEntity = new NodeEntity()
+ nodeEntity.node = nodeDTO
+ def config = new NodeManagerTool()
+
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT) >> "8081"
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_HOST) >> "localhost"
+ clientFactory.getClient(_,_) >> client
+ client.resource(_ as String) >> resource
+ resource.type(_) >> builder
+ builder.get(ClientResponse.class) >> response
+ builder.header(_,_) >> builder
+ builder.put(_,_) >> response
+ response.getStatus() >> 200
+ response.getEntity(ClusterEntity.class) >> clusterEntity
+ response.getEntity(NodeEntity.class) >> nodeEntity
+ clusterEntity.getCluster() >> clusterDTO
+ clusterDTO.getNodes() >> nodeDTOs
+ nodeDTO.address >> "localhost"
+
+ expect:
+ config.parse(clientFactory,["-b","src/test/resources/notify/conf_secure/bootstrap.conf","-d","/bogus/nifi/dir","-o","disconnect","-u","https://localhost:8080,https://localhost1:8080","-p","ydavis@nifi"] as String[])
+
+ }
+
+ def "parse args and delete secured node"(){
+
+ setup:
+ def NiFiProperties niFiProperties = Mock NiFiProperties
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def ClusterEntity clusterEntity = Mock ClusterEntity
+ def ClusterDTO clusterDTO = Mock ClusterDTO
+ def NodeDTO nodeDTO = new NodeDTO()
+ nodeDTO.address = "localhost"
+ nodeDTO.nodeId = "1"
+ nodeDTO.status = "CONNECTED"
+ def List nodeDTOs = [nodeDTO]
+ def NodeEntity nodeEntity = new NodeEntity()
+ nodeEntity.node = nodeDTO
+ def config = new NodeManagerTool()
+
+
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT) >> "8081"
+ niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_HOST) >> "localhost"
+ clientFactory.getClient(_,_) >> client
+ client.resource(_ as String) >> resource
+ resource.type(_) >> builder
+ builder.get(ClientResponse.class) >> response
+ builder.header(_,_) >> builder
+ builder.put(_,_) >> response
+ builder.delete(ClientResponse.class,_) >> response
+ response.getStatus() >> 200
+ response.getEntity(ClusterEntity.class) >> clusterEntity
+ response.getEntity(NodeEntity.class) >> nodeEntity
+ clusterEntity.getCluster() >> clusterDTO
+ clusterDTO.getNodes() >> nodeDTOs
+ nodeDTO.address >> "localhost"
+
+ expect:
+ config.parse(clientFactory,["-b","src/test/resources/notify/conf_secure/bootstrap.conf","-d","/bogus/nifi/dir","-o","remove","-u","https://localhost:8080,https://localhost1:8080","-p","ydavis@nifi"] as String[])
+
+ }
+
}
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy
index 57468c075d..a0ec50fb89 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy
@@ -21,12 +21,19 @@ import com.sun.jersey.api.client.Client
import com.sun.jersey.api.client.ClientResponse
import com.sun.jersey.api.client.WebResource
import org.apache.commons.cli.ParseException
+import org.apache.commons.lang3.SystemUtils
import org.apache.nifi.toolkit.admin.client.ClientFactory
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandaloneCommandLine
import org.junit.Rule
import org.junit.contrib.java.lang.system.ExpectedSystemExit
import org.junit.contrib.java.lang.system.SystemOutRule
import spock.lang.Specification
+import javax.ws.rs.core.Response
+import java.nio.file.Files
+import java.nio.file.attribute.PosixFilePermission
+
class NotificationToolSpec extends Specification{
@Rule
@@ -104,7 +111,7 @@ class NotificationToolSpec extends Specification{
def config = new NotificationTool()
when:
- config.notifyCluster(clientFactory,"src/test/resources/notify/conf/nifi.properties","src/test/resources/notify/conf/bootstrap.conf","/bogus/nifi/dir","shutting down in 30 seconds","WARN")
+ config.notifyCluster(clientFactory,"src/test/resources/notify/conf/nifi.properties","src/test/resources/notify/conf/bootstrap.conf","/bogus/nifi/dir","shutting down in 30 seconds","WARN",null)
then:
@@ -116,9 +123,21 @@ class NotificationToolSpec extends Specification{
}
- def "cluster message failed"(){
+ def "send secured cluster cluster message successfully"(){
given:
+
+ def File tmpDir = setupTmpDir()
+ def File testDir = new File("target/tmp/keys")
+ def toolkitCommandLine = ["-O", "-o",testDir.absolutePath,"-n","localhost","-C", "CN=user1","-S", "badKeyPass", "-K", "badKeyPass", "-P", "badTrustPass"]
+
+ TlsToolkitStandaloneCommandLine tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine()
+ tlsToolkitStandaloneCommandLine.parse(toolkitCommandLine as String[])
+ new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig())
+
+ def bootstrapConfFile = "src/test/resources/notify/conf/bootstrap.conf"
+ def nifiPropertiesFile = "src/test/resources/notify/conf/nifi-secured.properties"
+
def ClientFactory clientFactory = Mock ClientFactory
def Client client = Mock Client
def WebResource resource = Mock WebResource
@@ -128,7 +147,38 @@ class NotificationToolSpec extends Specification{
def config = new NotificationTool()
when:
- config.notifyCluster(clientFactory,"src/test/resources/notify/conf/nifi.properties","src/test/resources/notify/conf/bootstrap.conf","/bogus/nifi/dir","shutting down in 30 seconds","WARN")
+ config.notifyCluster(clientFactory,nifiPropertiesFile,bootstrapConfFile,"/bogus/nifi/dir","shutting down in 30 seconds","WARN","ydavis@nifi")
+
+ then:
+
+ 1 * clientFactory.getClient(_,_) >> client
+ 1 * client.resource(_ as String) >> resource
+ 1 * resource.type(_) >> builder
+ 1 * builder.header(_,_) >> builder
+ 1 * builder.post(_,_) >> response
+ 1 * response.getStatus() >> 200
+
+ cleanup:
+ tmpDir.deleteDir()
+
+ }
+
+
+
+ def "cluster message failed"(){
+
+ given:
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+ def Response.StatusType statusType = Mock Response.StatusType
+
+ def config = new NotificationTool()
+
+ when:
+ config.notifyCluster(clientFactory,"src/test/resources/notify/conf/nifi.properties","src/test/resources/notify/conf/bootstrap.conf","/bogus/nifi/dir","shutting down in 30 seconds","WARN","ydavis@nifi")
then:
@@ -137,8 +187,47 @@ class NotificationToolSpec extends Specification{
1 * resource.type(_) >> builder
1 * builder.post(_,_) >> response
1 * response.getStatus() >> 403
+ 1 * response.getEntity(String.class) >> "Unauthorized User"
def e = thrown(RuntimeException)
- e.message == "Failed with HTTP error code: 403"
+ e.message == "Failed with HTTP error code 403 with reason: Unauthorized User"
+
+ }
+
+ def "send secured cluster cluster message fails due to missing proxy dn"(){
+
+ given:
+
+ def File tmpDir = setupTmpDir()
+ def File testDir = new File("target/tmp/keys")
+ def toolkitCommandLine = ["-O", "-o",testDir.absolutePath,"-n","localhost","-C", "CN=user1","-S", "badKeyPass", "-K", "badKeyPass", "-P", "badTrustPass"]
+
+ TlsToolkitStandaloneCommandLine tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine()
+ tlsToolkitStandaloneCommandLine.parse(toolkitCommandLine as String[])
+ new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig())
+
+ def bootstrapConfFile = "src/test/resources/notify/conf/bootstrap.conf"
+ def nifiPropertiesFile = "src/test/resources/notify/conf/nifi-secured.properties"
+
+ def ClientFactory clientFactory = Mock ClientFactory
+ def Client client = Mock Client
+ def WebResource resource = Mock WebResource
+ def WebResource.Builder builder = Mock WebResource.Builder
+ def ClientResponse response = Mock ClientResponse
+
+ def config = new NotificationTool()
+
+ when:
+ config.notifyCluster(clientFactory,nifiPropertiesFile,bootstrapConfFile,"/bogus/nifi/dir","shutting down in 30 seconds","WARN",null)
+
+ then:
+
+ 1 * clientFactory.getClient(_,_) >> client
+ 1 * client.resource(_ as String) >> resource
+ def e = thrown(UnsupportedOperationException)
+ e.message == "Proxy DN is required for sending a notification to this node or cluster"
+
+ cleanup:
+ tmpDir.deleteDir()
}
@@ -166,6 +255,25 @@ class NotificationToolSpec extends Specification{
}
+ def setFilePermissions(File file, List permissions = []) {
+ if (SystemUtils.IS_OS_WINDOWS) {
+ file?.setReadable(permissions.contains(PosixFilePermission.OWNER_READ))
+ file?.setWritable(permissions.contains(PosixFilePermission.OWNER_WRITE))
+ file?.setExecutable(permissions.contains(PosixFilePermission.OWNER_EXECUTE))
+ } else {
+ Files.setPosixFilePermissions(file?.toPath(), permissions as Set)
+ }
+ }
+ def setupTmpDir(String tmpDirPath = "target/tmp/") {
+ File tmpDir = new File(tmpDirPath)
+ tmpDir.mkdirs()
+ setFilePermissions(tmpDir, [PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE,
+ PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE, PosixFilePermission.GROUP_EXECUTE,
+ PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_WRITE, PosixFilePermission.OTHERS_EXECUTE])
+ tmpDir
+ }
+
+
}
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/bootstrap.conf
new file mode 100644
index 0000000000..6dbcb577a8
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/bootstrap.conf
@@ -0,0 +1,74 @@
+#
+# 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.
+#
+
+# Java command to use when running NiFi
+java=java
+
+# Username to use when running NiFi. This value will be ignored on Windows.
+run.as=
+
+# Configure where NiFi's lib and conf directories live
+ lib.dir=./lib
+conf.dir=./conf_secure
+
+# How long to wait after telling NiFi to shutdown before explicitly killing the Process
+graceful.shutdown.seconds=20
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms1024m
+java.arg.3=-Xmx1024m
+
+# Enable Remote Debugging
+java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# The G1GC is still considered experimental but has proven to be very advantageous in providing great
+# performance without significant "stop-the-world" delays.
+java.arg.13=-XX:+UseG1GC
+
+#Set headless mode by default
+java.arg.14=-Djava.awt.headless=true
+
+# Master key in hexadecimal format for encrypted sensitive configuration values
+nifi.bootstrap.sensitive.key=
+
+###
+# Notification Services for notifying interested parties when NiFi is stopped, started, dies
+###
+
+# XML File that contains the definitions of the notification services
+ notification.services.file=./conf/bootstrap-notification-services.xml
+
+# In the case that we are unable to send a notification for an event, how many times should we retry?
+notification.max.attempts=5
+
+# Comma-separated list of identifiers that are present in the notification.services.file; which services should be used to notify when NiFi is started?
+#nifi.start.notification.services=email-notification
+
+# Comma-separated list of identifiers that are present in the notification.services.file; which services should be used to notify when NiFi is stopped?
+#nifi.stop.notification.services=email-notification
+
+# Comma-separated list of identifiers that are present in the notification.services.file; which services should be used to notify when NiFi dies?
+#nifi.dead.notification.services=email-notification
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/nifi.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/nifi.properties
new file mode 100644
index 0000000000..d3e2990a9d
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf_secure/nifi.properties
@@ -0,0 +1,107 @@
+# 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=./conf/flow.xml.gz
+nifi.flow.configuration.archive.dir=./conf/archive/
+nifi.task.configuration.file=./conf/reporting-tasks.xml
+nifi.service.configuration.file=./conf/controller-services.xml
+nifi.database.directory=./database_repository
+nifi.flowfile.repository.directory=./flowfile_repository
+nifi.flowfile.repository.partitions=4096
+nifi.flowfile.repository.checkpoint.millis=120000
+nifi.content.repository.directory.default=./content_repository
+nifi.provenance.repository.capacity=25000
+nifi.templates.directory=./conf/templates
+nifi.version=1.2.0-SNAPSHOT
+nifi.ui.banner.text=DEFAULT BANNER
+nifi.ui.autorefresh.interval.seconds=30
+nifi.flowcontroller.autoStartProcessors=true
+nifi.flowcontroller.schedulestrategy=delay
+nifi.flowcontroller.minimum.nanoseconds=1000000
+nifi.flowcontroller.graceful.shutdown.seconds=10
+nifi.nar.library.directory=./lib
+nifi.nar.working.directory=./work/nar/
+nifi.flowservice.writedelay.seconds=2
+nifi.sensitive.props.key=REPLACE_ME
+nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
+nifi.sensitive.props.provider=BC
+nifi.h2.repository.maxmemoryrows=100000
+nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
+nifi.h2.max.connections=20
+nifi.h2.login.timeout=500
+#For testing purposes. Default value should actually be empty!
+nifi.remote.input.socket.port=5000
+nifi.remote.input.secure=true
+
+# web properties #
+nifi.web.war.directory=./lib
+nifi.web.http.host=
+nifi.web.http.port=
+nifi.web.https.host=
+nifi.web.https.port=5050
+nifi.web.jetty.working.directory=./work/jetty
+
+# security properties #
+nifi.security.keystore=target/tmp/keys/localhost/keystore.jks
+nifi.security.keystoreType=JKS
+nifi.security.keystorePasswd=badKeyPass
+nifi.security.keyPasswd=badKeyPass
+nifi.security.truststore=target/tmp/keys/localhost/truststore.jks
+nifi.security.truststoreType=JKS
+nifi.security.truststorePasswd=badTrustPass
+nifi.security.needClientAuth=true
+nifi.security.user.authorizer=
+
+# cluster common properties (cluster manager and nodes must have same values) #
+nifi.cluster.protocol.heartbeat.tick.seconds=10
+nifi.cluster.protocol.is.secure=true
+nifi.cluster.protocol.socket.timeout.ms=30000
+nifi.cluster.protocol.connection.handshake.timeout.seconds=45
+# 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.ms=500
+nifi.cluster.protocol.multicast.service.locator.attempts=3
+nifi.cluster.protocol.multicast.service.locator.attempts.delay.seconds=1
+#For testing purposes. Default value should actually be empty!
+nifi.cluster.remote.input.socket.port=5000
+nifi.cluster.remote.input.secure=true
+
+# cluster node properties (only configure for cluster nodes) #
+nifi.cluster.is.node=true
+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=true
+nifi.cluster.manager.address=localhost
+nifi.cluster.manager.protocol.port=3030
+nifi.cluster.manager.authority.provider.port=4040
+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.ms=30000
+nifi.cluster.manager.node.api.read.timeout.ms=30000
+nifi.cluster.manager.node.api.request.threads=10
+nifi.cluster.manager.flow.retrieval.delay.seconds=5
+nifi.cluster.manager.protocol.threads=10
+nifi.cluster.manager.safemode.seconds=0