You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/04/25 06:11:00 UTC

[2/3] nifi git commit: NIFI-3695 - created the nifi admin toolkit which includes shell scripts and classes to support notification and basic node management in standalone and clustered nifi.

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactorySpec.groovy
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactorySpec.groovy b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactorySpec.groovy
new file mode 100644
index 0000000..a37b1c1
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactorySpec.groovy
@@ -0,0 +1,247 @@
+/*
+ * 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.toolkit.admin.client
+
+import org.apache.commons.lang3.SystemUtils
+import org.apache.nifi.properties.NiFiPropertiesLoader
+import org.apache.nifi.security.util.CertificateUtils
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandaloneCommandLine
+import org.apache.nifi.util.NiFiProperties
+import org.bouncycastle.asn1.x500.X500Name
+import org.bouncycastle.asn1.x500.X500NameBuilder
+import org.bouncycastle.asn1.x500.style.BCStyle
+import org.bouncycastle.asn1.x509.Extension
+import org.bouncycastle.asn1.x509.Extensions
+import org.bouncycastle.asn1.x509.ExtensionsGenerator
+import org.bouncycastle.asn1.x509.GeneralName
+import org.bouncycastle.asn1.x509.GeneralNames
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
+import org.bouncycastle.cert.X509CertificateHolder
+import org.bouncycastle.cert.X509v3CertificateBuilder
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import org.bouncycastle.operator.ContentSigner
+import org.bouncycastle.operator.OperatorCreationException
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
+import spock.lang.Specification
+
+import javax.net.ssl.SSLSession
+import java.nio.file.Files
+import java.nio.file.attribute.PosixFilePermission
+import java.security.InvalidKeyException
+import java.security.KeyPair
+import java.security.KeyPairGenerator
+import java.security.NoSuchAlgorithmException
+import java.security.NoSuchProviderException
+import java.security.SignatureException
+import java.security.cert.Certificate
+import java.security.cert.CertificateException
+import java.security.cert.X509Certificate
+import java.util.concurrent.TimeUnit
+
+class NiFiClientFactorySpec extends Specification {
+
+    private static final int KEY_SIZE = 2048
+    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA"
+    private static final int DAYS_IN_YEAR = 365
+    private static final String ISSUER_DN = "CN=NiFi Test CA,OU=Security,O=Apache,ST=CA,C=US"
+
+    def "get client for unsecure nifi"(){
+
+        given:
+        def NiFiProperties niFiProperties = Mock NiFiProperties
+        def clientFactory = new NiFiClientFactory()
+
+        when:
+        def client = clientFactory.getClient(niFiProperties,"src/test/resources/notify")
+
+        then:
+        client
+
+    }
+
+    def "get client for secured nifi"(){
+
+        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 key = NiFiPropertiesLoader.extractKeyFromBootstrapFile(bootstrapConfFile)
+        def NiFiProperties niFiProperties = NiFiPropertiesLoader.withKey(key).load(nifiPropertiesFile)
+        def clientFactory = new NiFiClientFactory()
+
+        when:
+        def client = clientFactory.getClient(niFiProperties,"src/test/resources/notify")
+
+        then:
+        client
+
+        cleanup:
+        tmpDir.deleteDir()
+
+    }
+
+    def "should verify CN in certificate based on subjectDN"(){
+
+        given:
+        final String EXPECTED_DN = "CN=client.nifi.apache.org,OU=Security,O=Apache,ST=CA,C=US"
+        Certificate[] certificateChain = generateCertificateChain(EXPECTED_DN,ISSUER_DN)
+        def mockSession = Mock(SSLSession)
+        NiFiClientFactory.NiFiHostnameVerifier verifier = new NiFiClientFactory.NiFiHostnameVerifier()
+        mockSession.getPeerCertificates() >> certificateChain
+
+        when:
+        def verified = verifier.verify("client.nifi.apache.org",mockSession)
+
+        then:
+        verified
+
+    }
+
+    def "should not verify based on no certificate chain"(){
+
+        given:
+        final String EXPECTED_DN = "CN=client.nifi.apache.org, OU=Security, O=Apache, ST=CA, C=US"
+        Certificate[] certificateChain = [] as Certificate[]
+        def mockSession = Mock(SSLSession)
+        NiFiClientFactory.NiFiHostnameVerifier verifier = new NiFiClientFactory.NiFiHostnameVerifier()
+        mockSession.getPeerCertificates() >> certificateChain
+
+        when:
+        def notVerified = !verifier.verify("client.nifi.apache.org",mockSession)
+
+        then:
+        notVerified
+
+    }
+
+    def "should not verify based on multiple CN values"(){
+
+        given:
+        final KeyPair issuerKeyPair = generateKeyPair()
+        KeyPair keyPair = generateKeyPair()
+        final X509Certificate issuerCertificate = CertificateUtils.generateSelfSignedX509Certificate(issuerKeyPair,ISSUER_DN, SIGNATURE_ALGORITHM, DAYS_IN_YEAR)
+
+        ContentSigner sigGen = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(issuerKeyPair.getPrivate());
+        SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.public.getEncoded());
+        Date startDate = new Date();
+        Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(DAYS_IN_YEAR));
+
+        def X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE)
+        nameBuilder.addRDN(BCStyle.CN,"client.nifi.apache.org,nifi.apache.org")
+        def name = nameBuilder.build()
+
+        X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(new X500Name(issuerCertificate.getSubjectX500Principal().getName()),
+                BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, name,
+                subPubKeyInfo);
+
+        X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
+        Certificate certificate = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
+
+        Certificate[] certificateChain = [certificate,issuerCertificate] as Certificate[]
+        def mockSession = Mock(SSLSession)
+        NiFiClientFactory.NiFiHostnameVerifier verifier = new NiFiClientFactory.NiFiHostnameVerifier()
+        mockSession.getPeerCertificates() >> certificateChain
+
+
+        when:
+        def notVerified = !verifier.verify("client.nifi.apache.org",mockSession)
+
+        then:
+        notVerified
+
+    }
+
+    def "should verify appropriately CN in certificate based on SAN"(){
+
+        given:
+
+        final List<String> SANS = ["127.0.0.1", "nifi.apache.org"]
+        def gns = SANS.collect { String san ->
+            new GeneralName(GeneralName.dNSName, san)
+        }
+        def generalNames = new GeneralNames(gns as GeneralName[])
+        ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator()
+        extensionsGenerator.addExtension(Extension.subjectAlternativeName, false, generalNames)
+        Extensions extensions = extensionsGenerator.generate()
+
+        final String EXPECTED_DN = "CN=client.nifi.apache.org,OU=Security,O=Apache,ST=CA,C=US"
+        final KeyPair issuerKeyPair = generateKeyPair()
+        final X509Certificate issuerCertificate = CertificateUtils.generateSelfSignedX509Certificate(issuerKeyPair,ISSUER_DN, SIGNATURE_ALGORITHM, DAYS_IN_YEAR)
+        final X509Certificate certificate = generateIssuedCertificate(EXPECTED_DN, issuerCertificate,extensions, issuerKeyPair)
+        Certificate[] certificateChain = [certificate, issuerCertificate] as X509Certificate[]
+        def mockSession = Mock(SSLSession)
+        NiFiClientFactory.NiFiHostnameVerifier verifier = new NiFiClientFactory.NiFiHostnameVerifier()
+        mockSession.getPeerCertificates() >> certificateChain
+
+        when:
+        def verified = verifier.verify("nifi.apache.org",mockSession)
+        def notVerified = !verifier.verify("fake.apache.org",mockSession)
+
+
+        then:
+        verified
+        notVerified
+
+    }
+
+    def KeyPair generateKeyPair() throws NoSuchAlgorithmException {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA")
+        keyPairGenerator.initialize(KEY_SIZE)
+        return keyPairGenerator.generateKeyPair()
+    }
+
+    def X509Certificate generateIssuedCertificate(String dn, X509Certificate issuer,Extensions extensions, KeyPair issuerKey) throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, SignatureException, InvalidKeyException, OperatorCreationException {
+        KeyPair keyPair = generateKeyPair()
+        return CertificateUtils.generateIssuedCertificate(dn, keyPair.getPublic(),extensions, issuer, issuerKey, SIGNATURE_ALGORITHM, DAYS_IN_YEAR)
+    }
+
+    def X509Certificate[] generateCertificateChain(String dn,String issuerDn) {
+        final KeyPair issuerKeyPair = generateKeyPair()
+        final X509Certificate issuerCertificate = CertificateUtils.generateSelfSignedX509Certificate(issuerKeyPair, issuerDn, SIGNATURE_ALGORITHM, DAYS_IN_YEAR)
+        final X509Certificate certificate = generateIssuedCertificate(dn, issuerCertificate,null, issuerKeyPair)
+        [certificate, issuerCertificate] as X509Certificate[]
+    }
+
+    def setFilePermissions(File file, List<PosixFilePermission> 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
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..32a1522
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientUtilSpec.groovy
@@ -0,0 +1,109 @@
+/*
+ * 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.toolkit.admin.client
+
+import com.sun.jersey.api.client.Client
+import com.sun.jersey.api.client.ClientResponse
+import com.sun.jersey.api.client.WebResource
+import org.apache.nifi.util.NiFiProperties
+import org.apache.nifi.web.api.entity.ClusterEntity
+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
+
+class NiFiClientUtilSpec extends Specification{
+
+    @Rule
+    public final ExpectedSystemExit exit = ExpectedSystemExit.none()
+
+    @Rule
+    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog()
+
+    def "build unsecure url successfully"(){
+
+        given:
+        def NiFiProperties niFiProperties = Mock NiFiProperties
+
+
+        when:
+        def url = NiFiClientUtil.getUrl(niFiProperties,"/nifi-api/controller/cluster/nodes/1")
+
+        then:
+
+        3 * niFiProperties.getProperty(_)
+        url == "http://localhost:8080/nifi-api/controller/cluster/nodes/1"
+    }
+
+
+    def "get 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, [])
+
+        then:
+
+        3 * niFiProperties.getProperty(_)
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.get(_) >> response
+        1 * response.getStatus() >> 200
+        1 * response.getEntity(ClusterEntity.class) >> clusterEntity
+        entity == clusterEntity
+
+    }
+
+    def "get cluster info fails"(){
+
+        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 Response.StatusType statusType = Mock Response.StatusType
+
+        when:
+
+        NiFiClientUtil.getCluster(client, niFiProperties, [])
+
+        then:
+
+        3 * niFiProperties.getProperty(_)
+        1 * client.resource(_ as String) >> resource
+        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."
+        def e = thrown(RuntimeException)
+        e.message == "Unable to obtain cluster information"
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..e482bbc
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/nodemanager/NodeManagerToolSpec.groovy
@@ -0,0 +1,414 @@
+
+/*
+ * 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.toolkit.admin.nodemanager
+
+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.nifi.toolkit.admin.client.ClientFactory
+import org.apache.nifi.util.NiFiProperties
+import org.apache.nifi.web.api.dto.ClusterDTO
+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.junit.Rule
+import org.junit.contrib.java.lang.system.ExpectedSystemExit
+import org.junit.contrib.java.lang.system.SystemOutRule
+import spock.lang.Specification
+
+class NodeManagerToolSpec extends Specification{
+
+    @Rule
+    public final ExpectedSystemExit exit = ExpectedSystemExit.none()
+
+    @Rule
+    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog()
+
+
+    def "print help and usage info"() {
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NodeManagerTool()
+
+        when:
+        config.parse(clientFactory,["-h"] as String[])
+
+        then:
+        systemOutRule.getLog().contains("usage: org.apache.nifi.toolkit.admin.nodemanager.NodeManagerTool")
+    }
+
+    def "throws exception missing bootstrap conf flag"() {
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NodeManagerTool()
+
+        when:
+        config.parse(clientFactory,["-d", "/install/nifi"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -b option"
+    }
+
+    def "throws exception missing directory"(){
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NodeManagerTool()
+
+        when:
+        config.parse(clientFactory,["-b","src/test/resources/notify/conf/bootstrap.conf"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -d option"
+    }
+
+    def "throws exception missing operation"(){
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NodeManagerTool()
+
+        when:
+        config.parse(clientFactory,["-b","src/test/resources/notify/conf/bootstrap.conf","-d", "/install/nifi"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -o option"
+    }
+
+    def "throws exception invalid operation"(){
+
+        given:
+        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"
+        nodeDTO.apiPort = 8080
+        def List<NodeDTO> 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.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"
+
+        when:
+        config.parse(clientFactory,["-b","src/test/resources/notify/conf/bootstrap.conf","-d","/install/nifi","-o","fake"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Invalid operation provided: fake"
+    }
+
+    def "get node info successfully"(){
+
+        given:
+        def NiFiProperties niFiProperties = Mock NiFiProperties
+        def ClusterEntity clusterEntity = Mock ClusterEntity
+        def ClusterDTO clusterDTO = Mock ClusterDTO
+        def NodeDTO nodeDTO = new NodeDTO()
+        nodeDTO.address = "1"
+        def List<NodeDTO> nodeDTOs = [nodeDTO]
+        def config = new NodeManagerTool()
+
+        when:
+        def entity = config.getCurrentNode(clusterEntity,niFiProperties)
+
+        then:
+
+        1 * clusterEntity.getCluster() >> clusterDTO
+        1 * clusterDTO.getNodes() >> nodeDTOs
+        2 * niFiProperties.getProperty(_) >> "1"
+        entity == nodeDTO
+
+    }
+
+    def "delete node successfully"(){
+
+        given:
+        def String url = "http://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)
+
+        then:
+
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.delete(_) >> response
+        1 * response.getStatus() >> 200
+
+    }
+
+    def "delete node failed"(){
+
+        given:
+        def String url = "http://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)
+
+        then:
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.delete(_) >> response
+        2 * response.getStatus() >> 403
+        def e = thrown(RuntimeException)
+        e.message == "Failed with HTTP error code: 403"
+
+    }
+
+    def "update node successfully"(){
+
+        given:
+        def String url = "http://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)
+
+        then:
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.put(_,_) >> response
+        1 * response.getStatus() >> 200
+        1 * response.getEntity(NodeEntity.class) >> nodeEntity
+        entity == nodeEntity
+
+    }
+
+    def "update node fails"(){
+
+        given:
+        def String url = "http://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 config = new NodeManagerTool()
+
+        when:
+        config.updateNode(url,client,nodeDTO,NodeManagerTool.STATUS.DISCONNECTING)
+
+        then:
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.put(_,_) >> response
+        2 * response.getStatus() >> 403
+        def e = thrown(RuntimeException)
+        e.message == "Failed with HTTP error code: 403"
+
+    }
+
+    def "disconnect 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<NodeDTO> 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.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,["http://localhost:8080"])
+
+    }
+
+    def "connect 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 = "DISCONNECTED"
+        def List<NodeDTO> 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.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.connectNode(client, niFiProperties,["http://localhost:8080"])
+
+    }
+
+    def "remove 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<NodeDTO> 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.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.removeNode(client, niFiProperties,["http://localhost:8080"])
+
+    }
+
+    def "parse args and delete 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<NodeDTO> 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.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/bootstrap.conf","-d","/bogus/nifi/dir","-o","remove","-u","http://localhost:8080,http://localhost1:8080"] as String[])
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..57468c0
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/notify/NotificationToolSpec.groovy
@@ -0,0 +1,171 @@
+/*
+ * 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.toolkit.admin.notify
+
+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.nifi.toolkit.admin.client.ClientFactory
+import org.junit.Rule
+import org.junit.contrib.java.lang.system.ExpectedSystemExit
+import org.junit.contrib.java.lang.system.SystemOutRule
+import spock.lang.Specification
+
+class NotificationToolSpec extends Specification{
+
+    @Rule
+    public final ExpectedSystemExit exit = ExpectedSystemExit.none()
+
+    @Rule
+    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog()
+
+
+    def "print help and usage info"() {
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NotificationTool()
+
+        when:
+        config.parse(clientFactory,["-h"] as String[])
+
+        then:
+        systemOutRule.getLog().contains("usage: org.apache.nifi.toolkit.admin.notify.NotificationTool")
+    }
+
+    def "throws exception missing bootstrap conf flag"() {
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NotificationTool()
+
+        when:
+        config.parse(clientFactory,["-d", "/missing/bootstrap/conf"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -b option"
+    }
+
+    def "throws exception missing message"(){
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NotificationTool()
+
+        when:
+        config.parse(clientFactory,["-b","/tmp/fake/upgrade/conf","-v","-d","/bogus/nifi/dir"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -m option"
+    }
+
+    def "throws exception missing directory"(){
+
+        given:
+        def ClientFactory clientFactory = Mock ClientFactory
+        def config = new NotificationTool()
+
+        when:
+        config.parse(clientFactory,["-b","src/test/resources/notify/conf/bootstrap.conf","-m","shutting down in 30 seconds"] as String[])
+
+        then:
+        def e = thrown(ParseException)
+        e.message == "Missing -d option"
+    }
+
+
+    def "send cluster message successfully"(){
+
+        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 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")
+
+        then:
+
+        1 * clientFactory.getClient(_,_) >> client
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.post(_,_) >> response
+        1 * response.getStatus() >> 200
+
+    }
+
+    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 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")
+
+        then:
+
+        1 * clientFactory.getClient(_,_) >> client
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.post(_,_) >> response
+        1 * response.getStatus() >> 403
+        def e = thrown(RuntimeException)
+        e.message == "Failed with HTTP error code: 403"
+
+    }
+
+    def "parse comment and send cluster message successfully"(){
+
+        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 config = new NotificationTool()
+
+        when:
+        config.parse(clientFactory,["-b","src/test/resources/notify/conf/bootstrap.conf","-d","/bogus/nifi/dir","-m","shutting down in 30 seconds","-l","ERROR"] as String[])
+
+        then:
+
+        1 * clientFactory.getClient(_,_) >> client
+        1 * client.resource(_ as String) >> resource
+        1 * resource.type(_) >> builder
+        1 * builder.post(_,_) >> response
+        1 * response.getStatus() >> 200
+
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/util/AdminUtilSpec.groovy
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/util/AdminUtilSpec.groovy b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/util/AdminUtilSpec.groovy
new file mode 100644
index 0000000..854eefb
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/groovy/org/apache/nifi/toolkit/admin/util/AdminUtilSpec.groovy
@@ -0,0 +1,54 @@
+/*
+ * 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.toolkit.admin.util
+
+import spock.lang.Specification
+
+class AdminUtilSpec extends Specification{
+
+    def "get nifi version with version in properties"(){
+
+        setup:
+
+        def nifiConfDir = new File("src/test/resources/conf")
+        def nifiLibDir = new File("src/test/resources/lib")
+
+        when:
+
+        def version = AdminUtil.getNiFiVersion(nifiConfDir,nifiLibDir)
+
+        then:
+        version == "1.1.0"
+    }
+
+    def "get nifi version with version in nar"(){
+
+        setup:
+
+        def nifiConfDir = new File("src/test/resources/upgrade/conf")
+        def nifiLibDir = new File("src/test/resources/lib")
+
+        when:
+
+        def version = AdminUtil.getNiFiVersion(nifiConfDir,nifiLibDir)
+
+        then:
+        version == "1.2.0"
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/bootstrap.conf
new file mode 100644
index 0000000..a4a59f1
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/bootstrap.conf
@@ -0,0 +1,32 @@
+#
+# 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
+
+# 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/login-identity-providers.xml b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/login-identity-providers.xml
new file mode 100644
index 0000000..7666152
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/login-identity-providers.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  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.
+-->
+<!--
+    This file lists the login identity providers to use when running securely. In order
+    to use a specific provider it must be configured here and it's identifier
+    must be specified in the nifi.properties file.
+-->
+<loginIdentityProviders>
+    <!--
+        Identity Provider for users logging in with username/password against an LDAP server.
+
+        'Authentication Strategy' - How the connection to the LDAP server is authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP server to search for users.
+        'Manager Password' - The password of the manager that is used to bind to the LDAP server to
+            search for users.
+
+        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut down gracefully
+            before the target context is closed. Defaults to false.
+
+        'Referral Strategy' - Strategy for handling referrals. Possible values are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. ldap://<hostname>:<port>).
+        'User Search Base' - Base DN for searching for users (i.e. CN=Users,DC=example,DC=com).
+        'User Search Filter' - Filter for searching for users against the 'User Search Base'.
+            (i.e. sAMAccountName={0}). The user specified name is inserted into '{0}'.
+
+        'Identity Strategy' - Strategy to identify users. Possible values are USE_DN and USE_USERNAME.
+            The default functionality if this property is missing is USE_DN in order to retain
+            backward compatibility. USE_DN will use the full DN of the user entry if possible.
+            USE_USERNAME will use the username the user logged in with.
+        'Authentication Expiration' - The duration of how long the user authentication is valid
+            for. If the user never logs out, they will be required to log back in following
+            this duration.
+    -->
+    <!-- To enable the ldap-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN"></property>
+        <property name="Manager Password"></property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password"></property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password"></property>
+        <property name="TLS - Truststore Type"></property>
+        <property name="TLS - Client Auth"></property>
+        <property name="TLS - Protocol"></property>
+        <property name="TLS - Shutdown Gracefully"></property>
+
+        <property name="Referral Strategy">FOLLOW</property>
+        <property name="Connect Timeout">10 secs</property>
+        <property name="Read Timeout">10 secs</property>
+
+        <property name="Url"></property>
+        <property name="User Search Base"></property>
+        <property name="User Search Filter"></property>
+
+        <property name="Identity Strategy">USE_DN</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the ldap-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        Identity Provider for users logging in with username/password against a Kerberos KDC server.
+
+        'Default Realm' - Default realm to provide when user enters incomplete user principal (i.e. NIFI.APACHE.ORG).
+        'Authentication Expiration' - The duration of how long the user authentication is valid for. If the user never logs out, they will be required to log back in following this duration.
+    -->
+    <!-- To enable the kerberos-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>kerberos-provider</identifier>
+        <class>org.apache.nifi.kerberos.KerberosProvider</class>
+        <property name="Default Realm">NIFI.APACHE.ORG</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the kerberos-provider remove 2 lines. This is 2 of 2. -->
+</loginIdentityProviders>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/nifi.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/nifi.properties
new file mode 100644
index 0000000..c38a30a
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/conf/nifi.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+nifi.version=1.1.0
+nifi.cluster.is.node=true
+nifi.cluster.node.address=localhost
+nifi.cluster.node.protocol.port=8300
+nifi.cluster.node.protocol.threads=2
+nifi.cluster.node.event.history.size=
+nifi.cluster.node.connection.timeout=
+nifi.cluster.node.read.timeout=30
+nifi.cluster.firewall.file=
+nifi.cluster.flow.election.max.wait.time=1
+nifi.cluster.flow.election.max.candidates=
+nifi.fluster.an.old.variable=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/bootstrap.conf
new file mode 100644
index 0000000..5ff5cdd
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/bootstrap.conf
@@ -0,0 +1,32 @@
+#
+# 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=target/tmp/conf
+
+# 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/login-identity-providers.xml b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/login-identity-providers.xml
new file mode 100644
index 0000000..7666152
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/login-identity-providers.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  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.
+-->
+<!--
+    This file lists the login identity providers to use when running securely. In order
+    to use a specific provider it must be configured here and it's identifier
+    must be specified in the nifi.properties file.
+-->
+<loginIdentityProviders>
+    <!--
+        Identity Provider for users logging in with username/password against an LDAP server.
+
+        'Authentication Strategy' - How the connection to the LDAP server is authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP server to search for users.
+        'Manager Password' - The password of the manager that is used to bind to the LDAP server to
+            search for users.
+
+        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut down gracefully
+            before the target context is closed. Defaults to false.
+
+        'Referral Strategy' - Strategy for handling referrals. Possible values are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. ldap://<hostname>:<port>).
+        'User Search Base' - Base DN for searching for users (i.e. CN=Users,DC=example,DC=com).
+        'User Search Filter' - Filter for searching for users against the 'User Search Base'.
+            (i.e. sAMAccountName={0}). The user specified name is inserted into '{0}'.
+
+        'Identity Strategy' - Strategy to identify users. Possible values are USE_DN and USE_USERNAME.
+            The default functionality if this property is missing is USE_DN in order to retain
+            backward compatibility. USE_DN will use the full DN of the user entry if possible.
+            USE_USERNAME will use the username the user logged in with.
+        'Authentication Expiration' - The duration of how long the user authentication is valid
+            for. If the user never logs out, they will be required to log back in following
+            this duration.
+    -->
+    <!-- To enable the ldap-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN"></property>
+        <property name="Manager Password"></property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password"></property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password"></property>
+        <property name="TLS - Truststore Type"></property>
+        <property name="TLS - Client Auth"></property>
+        <property name="TLS - Protocol"></property>
+        <property name="TLS - Shutdown Gracefully"></property>
+
+        <property name="Referral Strategy">FOLLOW</property>
+        <property name="Connect Timeout">10 secs</property>
+        <property name="Read Timeout">10 secs</property>
+
+        <property name="Url"></property>
+        <property name="User Search Base"></property>
+        <property name="User Search Filter"></property>
+
+        <property name="Identity Strategy">USE_DN</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the ldap-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        Identity Provider for users logging in with username/password against a Kerberos KDC server.
+
+        'Default Realm' - Default realm to provide when user enters incomplete user principal (i.e. NIFI.APACHE.ORG).
+        'Authentication Expiration' - The duration of how long the user authentication is valid for. If the user never logs out, they will be required to log back in following this duration.
+    -->
+    <!-- To enable the kerberos-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>kerberos-provider</identifier>
+        <class>org.apache.nifi.kerberos.KerberosProvider</class>
+        <property name="Default Realm">NIFI.APACHE.ORG</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the kerberos-provider remove 2 lines. This is 2 of 2. -->
+</loginIdentityProviders>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/nifi.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/nifi.properties
new file mode 100644
index 0000000..c38a30a
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/external/conf/nifi.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+nifi.version=1.1.0
+nifi.cluster.is.node=true
+nifi.cluster.node.address=localhost
+nifi.cluster.node.protocol.port=8300
+nifi.cluster.node.protocol.threads=2
+nifi.cluster.node.event.history.size=
+nifi.cluster.node.connection.timeout=
+nifi.cluster.node.read.timeout=30
+nifi.cluster.firewall.file=
+nifi.cluster.flow.election.max.wait.time=1
+nifi.cluster.flow.election.max.candidates=
+nifi.fluster.an.old.variable=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/bootstrap.conf
new file mode 100644
index 0000000..a4a59f1
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/bootstrap.conf
@@ -0,0 +1,32 @@
+#
+# 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
+
+# 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/myid
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/myid b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/myid
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/myid
@@ -0,0 +1 @@
+1
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.tar.gz
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.tar.gz b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.tar.gz
new file mode 100644
index 0000000..c7bcdf4
Binary files /dev/null and b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.tar.gz differ

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.zip
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.zip b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.zip
new file mode 100644
index 0000000..68e7623
Binary files /dev/null and b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi-test-archive.zip differ

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi.properties
new file mode 100644
index 0000000..0aebbe8
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/filemanager/nifi.properties
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+nifi.version=1.1.0
+nifi.cluster.is.node=true
+nifi.cluster.node.address=localhost
+nifi.cluster.node.protocol.port=8300
+nifi.cluster.node.protocol.threads=2
+nifi.cluster.node.event.history.size=
+nifi.cluster.node.connection.timeout=
+nifi.cluster.node.read.timeout=30
+nifi.cluster.firewall.file=
+nifi.cluster.flow.election.max.wait.time=1
+nifi.cluster.flow.election.max.candidates=
+nifi.fluster.an.old.variable=true
+nifi.content.repository.directory.default=./content_repository
+nifi.provenance.repository.directory.default=./provenance_repository
+nifi.flowfile.repository.directory=./flowfile_repository
+nifi.database.directory=./database_repository
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/lib/nifi-framework-nar-1.2.0.nar
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/lib/nifi-framework-nar-1.2.0.nar b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/lib/nifi-framework-nar-1.2.0.nar
new file mode 100644
index 0000000..08faed3
Binary files /dev/null and b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/lib/nifi-framework-nar-1.2.0.nar differ

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/bootstrap.conf
new file mode 100644
index 0000000..744bfe9
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/bootstrap.conf
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+
+# JVM memory settings
+java.arg.2=-Xms512m
+java.arg.3=-Xmx512m

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/login-identity-providers.xml b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/login-identity-providers.xml
new file mode 100644
index 0000000..7666152
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/login-identity-providers.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  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.
+-->
+<!--
+    This file lists the login identity providers to use when running securely. In order
+    to use a specific provider it must be configured here and it's identifier
+    must be specified in the nifi.properties file.
+-->
+<loginIdentityProviders>
+    <!--
+        Identity Provider for users logging in with username/password against an LDAP server.
+
+        'Authentication Strategy' - How the connection to the LDAP server is authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP server to search for users.
+        'Manager Password' - The password of the manager that is used to bind to the LDAP server to
+            search for users.
+
+        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut down gracefully
+            before the target context is closed. Defaults to false.
+
+        'Referral Strategy' - Strategy for handling referrals. Possible values are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. ldap://<hostname>:<port>).
+        'User Search Base' - Base DN for searching for users (i.e. CN=Users,DC=example,DC=com).
+        'User Search Filter' - Filter for searching for users against the 'User Search Base'.
+            (i.e. sAMAccountName={0}). The user specified name is inserted into '{0}'.
+
+        'Identity Strategy' - Strategy to identify users. Possible values are USE_DN and USE_USERNAME.
+            The default functionality if this property is missing is USE_DN in order to retain
+            backward compatibility. USE_DN will use the full DN of the user entry if possible.
+            USE_USERNAME will use the username the user logged in with.
+        'Authentication Expiration' - The duration of how long the user authentication is valid
+            for. If the user never logs out, they will be required to log back in following
+            this duration.
+    -->
+    <!-- To enable the ldap-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN"></property>
+        <property name="Manager Password"></property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password"></property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password"></property>
+        <property name="TLS - Truststore Type"></property>
+        <property name="TLS - Client Auth"></property>
+        <property name="TLS - Protocol"></property>
+        <property name="TLS - Shutdown Gracefully"></property>
+
+        <property name="Referral Strategy">FOLLOW</property>
+        <property name="Connect Timeout">10 secs</property>
+        <property name="Read Timeout">10 secs</property>
+
+        <property name="Url"></property>
+        <property name="User Search Base"></property>
+        <property name="User Search Filter"></property>
+
+        <property name="Identity Strategy">USE_DN</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the ldap-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        Identity Provider for users logging in with username/password against a Kerberos KDC server.
+
+        'Default Realm' - Default realm to provide when user enters incomplete user principal (i.e. NIFI.APACHE.ORG).
+        'Authentication Expiration' - The duration of how long the user authentication is valid for. If the user never logs out, they will be required to log back in following this duration.
+    -->
+    <!-- To enable the kerberos-provider remove 2 lines. This is 1 of 2.
+    <provider>
+        <identifier>kerberos-provider</identifier>
+        <class>org.apache.nifi.kerberos.KerberosProvider</class>
+        <property name="Default Realm">NIFI.APACHE.ORG</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+    To enable the kerberos-provider remove 2 lines. This is 2 of 2. -->
+</loginIdentityProviders>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/nifi.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/nifi.properties
new file mode 100644
index 0000000..f85b567
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/no_rules/conf/nifi.properties
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+#upgrade test properties
+nifi.version=1.1.0
+nifi.cluster.is.node=
+nifi.cluster.node.address=
+nifi.cluster.node.protocol.port=
+nifi.cluster.node.protocol.threads=
+nifi.cluster.node.event.history.size=
+nifi.cluster.node.connection.timeout=
+nifi.cluster.node.read.timeout=
+nifi.cluster.firewall.file=
+nifi.cluster.flow.election.max.wait.time=
+nifi.cluster.flow.election.max.candidates=
+nifi.cluster.a.new.variable=
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/bootstrap.conf b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/bootstrap.conf
new file mode 100644
index 0000000..3125a17
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/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
+
+# 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

http://git-wip-us.apache.org/repos/asf/nifi/blob/c0f0462e/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/nifi-secured.properties
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/nifi-secured.properties b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/nifi-secured.properties
new file mode 100644
index 0000000..e498c75
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-admin/src/test/resources/notify/conf/nifi-secured.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=nifi 0.2.1-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=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=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