You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ym...@apache.org on 2016/11/15 03:41:53 UTC

[1/3] nifi git commit: NIFI-2654 Enabled encryption coverage for login-identity-providers.xml.

Repository: nifi
Updated Branches:
  refs/heads/master 8ad312516 -> 59fea1cb4


http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiline.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiline.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiline.xml
new file mode 100644
index 0000000..b9f64a9
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiline.xml
@@ -0,0 +1,111 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <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">
+            thisIsABadPassword
+        </property>
+
+        <property name="TLS - Keystore"></property>
+        <property
+                name="TLS - Keystore Password">thisIsABadPassword
+        </property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name=
+                          "TLS - Truststore Password">
+            thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiple-per-line.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiple-per-line.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiple-per-line.xml
new file mode 100644
index 0000000..2514863
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-multiple-per-line.xml
@@ -0,0 +1,101 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password" encryption="none">thisIsABadPassword</property><property name="TLS - Keystore"></property><property name="TLS - Keystore Password" encryption="">thisIsABadPassword</property><property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-single-line.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-single-line.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-single-line.xml
new file mode 100644
index 0000000..d208164
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-single-line.xml
@@ -0,0 +1,101 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <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">thisIsABadPassword</property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password">thisIsABadPassword</property><property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property><property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated.xml
new file mode 100644
index 0000000..5522c73
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated.xml
@@ -0,0 +1,105 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password">thisIsABadPassword</property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password">thisIsABadPassword</property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers.xml
new file mode 100644
index 0000000..7e2a3e1
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers.xml
@@ -0,0 +1,105 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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


[3/3] nifi git commit: NIFI-2654 Enabled encryption coverage for login-identity-providers.xml.

Posted by ym...@apache.org.
NIFI-2654 Enabled encryption coverage for login-identity-providers.xml.

Squashed commits:
[5dd22a9] NIFI-2654 Updated administration guide with login-identity-providers.xml flags.

Exposed master key retrieval code in NiFiPropertiesLoader.
Added logic to decrypt login identity providers XML configuration.
Updated login-identity-providers.xsd to include encryption scheme attribute.
Added unit tests. (+18 squashed commits)
Squashed commits:
[57c815f] NIFI-2654 Resolved issue where empty LIP property elements could not be encrypted.
Added unit test and resource.
[27d7309] NIFI-2654 Wired in serialization logic to write logic for LIP.
Added comprehensive unit test for LIP & NFP in same test.
[b450eb2] NIFI-2654 Finalized logic for preserving comments in LIP parsing.
[5aa6c9c] NIFI-2654 Added logic for maintaining XML formatting (comments and whitespace) for LIP.
Added unit tests (w/o encryption works; w/ does not).
[b53461f] NIFI-2654 Added unit test for full tool invocation migrating a login-identity-providers.xml file and updating file and bootstrap.conf with key.
[2d9686c] NIFI-2654 Updated tool description and various logging statements.
Added unit test for full tool invocation encrypting a login-identity-providers.xml file and updating file and bootstrap.conf with key.
[8c67cb2] NIFI-2654 Added logic to encrypt LIP XML content.
Added unit tests.
[8682d19] NIFI-2654 Added logic to handle "empty" (commented) LIP files.
Added unit tests.
[077230e] NIFI-2654 Fixed logic to decrypt multiline and multiple-per-line XML elements.
Added unit tests and resources.
[d5bb8da] NIFI-2654 Ignored unit test for unreadable conf directory because directory was causing Maven build issues.
Removed test resources.
[7e50506] NIFI-2654 Fixed AESSensitivePropertyProvider bug handling cipher text with whitespace.
Added unit test.
[b69a661] NIFI-2654 Fixed AESSensitivePropertyProviderFactoryTest to reflect absence of key causes errors.
[6f821b9] NIFI-2654 Added standard password to arbitrary encryption test for use in test resources.
[d289ffa] NIFI-2654 Added LIP XML decryption.
Added unit tests.
[a482245] NIFI-2654 Added LIP test resources.
[7204df4] NIFI-2654 Changed logic to only perform properties encryption when file path is provided.
[729e1df] NIFI-2654 Removed population of default file locations for bootstrap.conf, nifi.properties, and login-identity-providers.xml as not all files may be desired.
Added/updated unit tests.
[7dba5ef] NIFI-2654 Started LIP work (arguments & parsing).
Added unit tests.

Signed-off-by: Yolanda M. Davis <ym...@apache.org>

This closes #1216


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/59fea1cb
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/59fea1cb
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/59fea1cb

Branch: refs/heads/master
Commit: 59fea1cb4ed440ad0e68d96a412792c3e4551309
Parents: 8ad3125
Author: Andy LoPresto <al...@apache.org>
Authored: Mon Nov 7 20:36:59 2016 -0800
Committer: Yolanda M. Davis <ym...@apache.org>
Committed: Mon Nov 14 22:39:06 2016 -0500

----------------------------------------------------------------------
 .../src/main/asciidoc/administration-guide.adoc |  41 +-
 .../AESSensitivePropertyProvider.java           |   2 +
 .../nifi/properties/NiFiPropertiesLoader.java   |   8 +-
 ...SSensitivePropertyProviderFactoryTest.groovy |  20 +-
 .../AESSensitivePropertyProviderTest.groovy     |  30 +
 .../NiFiPropertiesLoaderGroovyTest.groovy       |   2 +
 .../unreadable_conf/bootstrap.conf              |  74 --
 .../unreadable_conf/nifi.properties             |  14 -
 .../LoginIdentityProviderFactoryBean.java       |  69 +-
 .../src/main/xsd/login-identity-providers.xsd   |   3 +-
 .../LoginIdentityProviderFactoryBeanTest.groovy | 141 ++++
 .../nifi/properties/ConfigEncryptionTool.groovy | 253 +++++-
 .../properties/ConfigEncryptionToolTest.groovy  | 766 ++++++++++++++++++-
 .../bootstrap_with_master_key_128.conf          |  74 ++
 ...n-identity-providers-commented-populated.xml | 107 +++
 .../login-identity-providers-commented.xml      | 107 +++
 ...login-identity-providers-populated-empty.xml | 105 +++
 ...-providers-populated-encrypted-multiline.xml | 110 +++
 ...rs-populated-encrypted-multiple-per-line.xml | 101 +++
 ...n-identity-providers-populated-encrypted.xml | 105 +++
 ...n-identity-providers-populated-multiline.xml | 111 +++
 ...ty-providers-populated-multiple-per-line.xml | 101 +++
 ...identity-providers-populated-single-line.xml | 101 +++
 .../login-identity-providers-populated.xml      | 105 +++
 .../test/resources/login-identity-providers.xml | 105 +++
 25 files changed, 2491 insertions(+), 164 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-docs/src/main/asciidoc/administration-guide.adoc
----------------------------------------------------------------------
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 2ce6564..be2e684 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -987,17 +987,19 @@ The default encryption algorithm utilized is AES/GCM 128/256-bit. 128-bit is use
 
 You can use the following command line options with the `encrypt-config` tool:
 
-* `-b,--bootstrapConf <arg>`          The bootstrap.conf file to persist master key
-* `-e,--oldKey <arg>`                 The old raw hexadecimal key to use during key migration
-* `-h,--help`                         Prints this usage message
-* `-k,--key <arg>`                    The raw hexadecimal key to use to encrypt the sensitive properties
-* `-m,--migrate`                      If provided, the sensitive properties will be re-encrypted with a new key
-* `-n,--niFiProperties <arg>`         The nifi.properties file containing unprotected config values (will be overwritten)
-* `-o,--outputNiFiProperties <arg>`   The destination nifi.properties file containing protected config values (will not modify input nifi.properties)
-* `-p,--password <arg>`               The password from which to derive the key to use to encrypt the sensitive properties
-* `-r,--useRawKey`                    If provided, the secure console will prompt for the raw key value in hexadecimal form
-* `-v,--verbose`                      Sets verbose mode (default false)
-* `-w,--oldPassword <arg>`            The old password from which to derive the key during migration
+* `-b,--bootstrapConf <arg>`                The bootstrap.conf file to persist master key
+* `-e,--oldKey <arg>`                       The old raw hexadecimal key to use during key migration
+* `-h,--help`                               Prints this usage message
+* `-k,--key <arg>`                          The raw hexadecimal key to use to encrypt the sensitive properties
+* `-m,--migrate`                            If provided, the sensitive properties will be re-encrypted with a new key
+* `-n,--niFiProperties <arg>`               The nifi.properties file containing unprotected config values (will be overwritten)
+* `-o,--outputNiFiProperties <arg>`         The destination nifi.properties file containing protected config values (will not modify input nifi.properties)
+* `-p,--password <arg>`                     The password from which to derive the key to use to encrypt the sensitive properties
+* `-r,--useRawKey`                          If provided, the secure console will prompt for the raw key value in hexadecimal form
+* `-v,--verbose`                            Sets verbose mode (default false)
+* `-w,--oldPassword <arg>`                  The old password from which to derive the key during migration
+* `-l,--loginIdentityProviders <arg>`       The login-identity-providers.xml file containing unprotected config values (will be overwritten)
+* `-i,--outputLoginIdentityProviders <arg>` The destination login-identity-providers.xml file containing protected config values (will not modify input login-identity-providers.xml)
 
 As an example of how the tool works, assume that you have installed the tool on a machine supporting 256-bit encryption and with the following existing values in the 'nifi.properties' file:
 
@@ -1058,6 +1060,23 @@ Sensitive configuration values are encrypted by the tool by default, however you
 
 If the 'nifi.properties' file already has valid protected values, those property values are not modified by the tool.
 
+When applied to 'login-identity-providers.xml', the property elements are updated with an `encryption` attribute:
+
+----
+<!-- LDAP Provider -->
+<provider>
+       <identifier>ldap-provider</identifier>
+       <class>org.apache.nifi.ldap.LdapProvider</class>
+       <property name="Authentication Strategy">START_TLS</property>
+       <property name="Manager DN">someuser</property>
+       <property name="Manager Password" encryption="aes/gcm/128">q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA</property>
+       <property name="TLS - Keystore"></property>
+       <property name="TLS - Keystore Password" encryption="aes/gcm/128">Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g</property>
+       <property name="TLS - Keystore Type"></property>
+      ...
+   </provider>
+----
+
 In order to change the key used to encrypt the sensitive values, indicate *migration mode* using the `-m` or `--migrate` flag, provide the new key or password using the `-k` or `-p` flags as usual, and provide the existing key or password using `-e` or `-w` respectively. This will allow the toolkit to decrypt the existing values and re-encrypt them, and update `bootstrap.conf` with the new key. Only one of the key or password needs to be specified for each phase (old vs. new), and any combination is sufficient:
 
 * old key -> new key

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/AESSensitivePropertyProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/AESSensitivePropertyProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/AESSensitivePropertyProvider.java
index 770d55d..1df398e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/AESSensitivePropertyProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/AESSensitivePropertyProvider.java
@@ -217,6 +217,8 @@ public class AESSensitivePropertyProvider implements SensitivePropertyProvider {
             throw new IllegalArgumentException("The cipher text does not contain the delimiter " + DELIMITER + " -- it should be of the form Base64(IV) || Base64(cipherText)");
         }
 
+        protectedValue = protectedValue.trim();
+
         final String IV_B64 = protectedValue.substring(0, protectedValue.indexOf(DELIMITER));
         byte[] iv = Base64.decode(IV_B64);
         if (iv.length < IV_LENGTH) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java
index 7f89b3d..20b5191 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java
@@ -102,7 +102,13 @@ public class NiFiPropertiesLoader {
         }
     }
 
-    private static String extractKeyFromBootstrapFile() throws IOException {
+    /**
+     * Returns the key (if any) used to encrypt sensitive properties, extracted from {@code $NIFI_HOME/conf/bootstrap.conf}.
+     *
+     * @return the key in hexadecimal format
+     * @throws IOException if the file is not readable
+     */
+    public static String extractKeyFromBootstrapFile() throws IOException {
         // Guess at location of bootstrap.conf file from nifi.properties file
         String defaultNiFiPropertiesPath = getDefaultFilePath();
         File propertiesFile = new File(defaultNiFiPropertiesPath);

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderFactoryTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderFactoryTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderFactoryTest.groovy
index e18ac93..115fca6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderFactoryTest.groovy
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderFactoryTest.groovy
@@ -56,17 +56,18 @@ class AESSensitivePropertyProviderFactoryTest extends GroovyTestCase {
 
     @Ignore("This is resolved in PR 1216")
     @Test
-    public void testShouldGetProviderWithoutKey() throws Exception {
+    public void testShouldNotGetProviderWithoutKey() throws Exception {
         // Arrange
         SensitivePropertyProviderFactory factory = new AESSensitivePropertyProviderFactory()
 
         // Act
-        SensitivePropertyProvider provider = factory.getProvider()
+        def msg = shouldFail(SensitivePropertyProtectionException) {
+            SensitivePropertyProvider provider = factory.getProvider()
+        }
+        logger.expected(msg)
 
         // Assert
-        assert provider instanceof AESSensitivePropertyProvider
-        assert !provider.@key
-        assert !provider.@cipher
+        assert msg == "The provider factory cannot generate providers without a key"
     }
 
     @Test
@@ -90,11 +91,12 @@ class AESSensitivePropertyProviderFactoryTest extends GroovyTestCase {
         SensitivePropertyProviderFactory factory = new AESSensitivePropertyProviderFactory("")
 
         // Act
-        SensitivePropertyProvider provider = factory.getProvider()
+        def msg = shouldFail(SensitivePropertyProtectionException) {
+            SensitivePropertyProvider provider = factory.getProvider()
+        }
+        logger.expected(msg)
 
         // Assert
-        assert provider instanceof AESSensitivePropertyProvider
-        assert !provider.@key
-        assert !provider.@cipher
+        assert msg == "The provider factory cannot generate providers without a key"
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderTest.groovy
index 3ca35f2..4c5a34d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderTest.groovy
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/AESSensitivePropertyProviderTest.groovy
@@ -239,6 +239,36 @@ class AESSensitivePropertyProviderTest extends GroovyTestCase {
     }
 
     @Test
+    public void testShouldUnprotectValueWithWhitespace() throws Exception {
+        // Arrange
+        final String PLAINTEXT = "This is a plaintext value"
+
+        Map<Integer, Cipher> encryptionCiphers = KEY_SIZES.collectEntries { int keySize ->
+            byte[] iv = new byte[IV_LENGTH]
+            secureRandom.nextBytes(iv)
+            [(keySize): getCipher(true, keySize, iv)]
+        }
+
+        Map<Integer, String> CIPHER_TEXTS = encryptionCiphers.collectEntries { Map.Entry<Integer, Cipher> e ->
+            String iv = encoder.encodeToString(e.value.getIV())
+            String cipherText = encoder.encodeToString(e.value.doFinal(PLAINTEXT.getBytes(StandardCharsets.UTF_8)))
+            [(e.key): "${iv}||${cipherText}"]
+        }
+        CIPHER_TEXTS.each { key, ct -> logger.expected("Cipher text for ${key} length key: ${ct}") }
+
+        // Act
+        Map<Integer, String> plaintexts = CIPHER_TEXTS.collectEntries { int keySize, String cipherText ->
+            SensitivePropertyProvider spp = new AESSensitivePropertyProvider(Hex.decode(getKeyOfSize(keySize)))
+            logger.info("Initialized ${spp.name} with key size ${keySize}")
+            [(keySize): spp.unprotect("\t" + cipherText + "\n")]
+        }
+        plaintexts.each { ks, pt -> logger.info("Decrypted for ${ks} length key: ${pt}") }
+
+        // Assert
+        assert plaintexts.every { int ks, String pt -> pt == PLAINTEXT }
+    }
+
+    @Test
     public void testShouldHandleUnprotectMalformedValue() throws Exception {
         // Arrange
         final String PLAINTEXT = "This is a plaintext value"

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/NiFiPropertiesLoaderGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/NiFiPropertiesLoaderGroovyTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/NiFiPropertiesLoaderGroovyTest.groovy
index eb1f081..980f86f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/NiFiPropertiesLoaderGroovyTest.groovy
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/groovy/org/apache/nifi/properties/NiFiPropertiesLoaderGroovyTest.groovy
@@ -22,6 +22,7 @@ import org.junit.After
 import org.junit.AfterClass
 import org.junit.Before
 import org.junit.BeforeClass
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -349,6 +350,7 @@ class NiFiPropertiesLoaderGroovyTest extends GroovyTestCase {
         Files.setPosixFilePermissions(unreadableFile.toPath(), originalPermissions)
     }
 
+    @Ignore("Unreadable conf directory breaks build")
     @Test
     public void testShouldNotExtractKeyFromUnreadableConfDir() throws Exception {
         // Arrange

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/bootstrap.conf b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/bootstrap.conf
deleted file mode 100755
index 9225126..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/bootstrap.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# 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=-Xms512m
-java.arg.3=-Xmx512m
-
-# 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=0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210
-
-###
-# 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
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/nifi.properties
deleted file mode 100644
index ae1e83e..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/resources/bootstrap_tests/unreadable_conf/nifi.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# 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.

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
index 26fae82..ee978db 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
@@ -16,6 +16,22 @@
  */
 package org.apache.nifi.web.security.spring;
 
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authentication.AuthenticationResponse;
 import org.apache.nifi.authentication.LoginCredentials;
@@ -31,6 +47,11 @@ import org.apache.nifi.authentication.generated.Property;
 import org.apache.nifi.authentication.generated.Provider;
 import org.apache.nifi.nar.ExtensionManager;
 import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.properties.AESSensitivePropertyProviderFactory;
+import org.apache.nifi.properties.NiFiPropertiesLoader;
+import org.apache.nifi.properties.SensitivePropertyProtectionException;
+import org.apache.nifi.properties.SensitivePropertyProvider;
+import org.apache.nifi.properties.SensitivePropertyProviderFactory;
 import org.apache.nifi.util.NiFiProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,22 +59,6 @@ import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.FactoryBean;
 import org.xml.sax.SAXException;
 
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import java.io.File;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  *
  */
@@ -64,6 +69,9 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
     private static final String JAXB_GENERATED_PATH = "org.apache.nifi.authentication.generated";
     private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
 
+    private static SensitivePropertyProviderFactory SENSITIVE_PROPERTY_PROVIDER_FACTORY;
+    private static SensitivePropertyProvider SENSITIVE_PROPERTY_PROVIDER;
+
     /**
      * Load the JAXBContext.
      */
@@ -185,12 +193,39 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
         final Map<String, String> providerProperties = new HashMap<>();
 
         for (final Property property : provider.getProperty()) {
-            providerProperties.put(property.getName(), property.getValue());
+            if (!StringUtils.isBlank(property.getEncryption())) {
+                String decryptedValue = decryptValue(property.getValue(), property.getEncryption());
+                providerProperties.put(property.getName(), decryptedValue);
+            } else {
+                providerProperties.put(property.getName(), property.getValue());
+            }
         }
 
         return new StandardLoginIdentityProviderConfigurationContext(provider.getIdentifier(), providerProperties);
     }
 
+    private String decryptValue(String cipherText, String encryptionScheme) throws SensitivePropertyProtectionException {
+            initializeSensitivePropertyProvider(encryptionScheme);
+        return SENSITIVE_PROPERTY_PROVIDER.unprotect(cipherText);
+    }
+
+    private static void initializeSensitivePropertyProvider(String encryptionScheme) throws SensitivePropertyProtectionException {
+        if (SENSITIVE_PROPERTY_PROVIDER == null || !SENSITIVE_PROPERTY_PROVIDER.getIdentifierKey().equalsIgnoreCase(encryptionScheme)) {
+            try {
+                String keyHex = getMasterKey();
+                SENSITIVE_PROPERTY_PROVIDER_FACTORY = new AESSensitivePropertyProviderFactory(keyHex);
+                SENSITIVE_PROPERTY_PROVIDER = SENSITIVE_PROPERTY_PROVIDER_FACTORY.getProvider();
+            } catch (IOException e) {
+                logger.error("Error extracting master key from bootstrap.conf for login identity provider decryption", e);
+                throw new SensitivePropertyProtectionException("Could not read master key from bootstrap.conf");
+            }
+        }
+    }
+
+    private static String getMasterKey() throws IOException {
+        return NiFiPropertiesLoader.extractKeyFromBootstrapFile();
+    }
+
     private void performMethodInjection(final LoginIdentityProvider instance, final Class loginIdentityProviderClass)
             throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/xsd/login-identity-providers.xsd
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/xsd/login-identity-providers.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/xsd/login-identity-providers.xsd
index 628f390..12a85ca 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/xsd/login-identity-providers.xsd
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/xsd/login-identity-providers.xsd
@@ -27,7 +27,8 @@
     <xs:complexType name="Property">
         <xs:simpleContent>
             <xs:extension base="xs:string">
-                <xs:attribute name="name" type="NonEmptyStringType"></xs:attribute>
+                <xs:attribute name="name" type="NonEmptyStringType"/>
+                <xs:attribute name="encryption" type="xs:string"/>
             </xs:extension>
         </xs:simpleContent>
     </xs:complexType>

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBeanTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBeanTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBeanTest.groovy
new file mode 100644
index 0000000..13eab19
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/groovy/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBeanTest.groovy
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.security.spring
+
+import org.apache.nifi.authentication.generated.Property
+import org.apache.nifi.authentication.generated.Provider
+import org.apache.nifi.properties.AESSensitivePropertyProvider
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import javax.crypto.Cipher
+import java.security.Security
+
+@RunWith(JUnit4.class)
+class LoginIdentityProviderFactoryBeanTest extends GroovyTestCase {
+    private static final Logger logger = LoggerFactory.getLogger(LoginIdentityProviderFactoryBeanTest.class)
+
+    // These blocks configure the constant values depending on JCE policies of the machine running the tests
+    private static final String KEY_HEX_128 = "0123456789ABCDEFFEDCBA9876543210"
+    private static final String KEY_HEX_256 = KEY_HEX_128 * 2
+    public static final String KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? KEY_HEX_256 : KEY_HEX_128
+
+    private static final String CIPHER_TEXT_128 = "6pqdM1urBEPHtj+L||ds0Z7RpqOA2321c/+7iPMfxDrqmH5Qx6UwQG0eIYB//3Ng"
+    private static final String CIPHER_TEXT_256 = "TepMCD7v3LAMF0KX||ydSRWPRl1/JXgTsZtfzCnDXu7a0lTLysjPL2I06EPUCHzw"
+    public static final String CIPHER_TEXT = isUnlimitedStrengthCryptoAvailable() ? CIPHER_TEXT_256 : CIPHER_TEXT_128
+
+    private static final String ENCRYPTION_SCHEME_128 = "aes/gcm/128"
+    private static final String ENCRYPTION_SCHEME_256 = "aes/gcm/256"
+    public static
+    final String ENCRYPTION_SCHEME = isUnlimitedStrengthCryptoAvailable() ? ENCRYPTION_SCHEME_256 : ENCRYPTION_SCHEME_128
+
+    private static final String PASSWORD = "thisIsABadPassword"
+
+    @BeforeClass
+    public static void setUpOnce() throws Exception {
+        Security.addProvider(new BouncyCastleProvider())
+
+        logger.metaClass.methodMissing = { String name, args ->
+            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
+        }
+    }
+
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER = new AESSensitivePropertyProvider(KEY_HEX)
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER = null
+        LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER_FACTORY = null
+    }
+
+    private static boolean isUnlimitedStrengthCryptoAvailable() {
+        Cipher.getMaxAllowedKeyLength("AES") > 128
+    }
+
+    private static int getKeyLength(String keyHex = KEY_HEX) {
+        keyHex?.size() * 4
+    }
+
+    @Ignore("Can't test without overloading static metaClass method")
+    @Test
+    void testShouldInitializeSensitivePropertyProvider() {
+        // Arrange
+        assert !LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER
+        assert !LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER_FACTORY
+
+        logger.info("Encryption scheme: ${ENCRYPTION_SCHEME}")
+
+        // Act
+        LoginIdentityProviderFactoryBean.initializeSensitivePropertyProvider(ENCRYPTION_SCHEME)
+
+        // Assert
+        assert LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER
+        assert LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER_FACTORY
+        assert LoginIdentityProviderFactoryBean.SENSITIVE_PROPERTY_PROVIDER.getIdentifierKey() == ENCRYPTION_SCHEME
+    }
+
+    @Test
+    void testShouldDecryptValue() {
+        // Arrange
+        logger.info("Encryption scheme: ${ENCRYPTION_SCHEME}")
+        logger.info("Cipher text: ${CIPHER_TEXT}")
+
+        // Act
+        String decrypted = new LoginIdentityProviderFactoryBean().decryptValue(CIPHER_TEXT, ENCRYPTION_SCHEME)
+        logger.info("Decrypted ${CIPHER_TEXT} -> ${decrypted}")
+
+        // Assert
+        assert decrypted == PASSWORD
+    }
+
+    @Test
+    void testShouldLoadEncryptedLoginIdentityProviderConfiguration() {
+        // Arrange
+        Provider encryptedProvider = new Provider()
+        encryptedProvider.identifier ="ldap-provider"
+        encryptedProvider.clazz = "org.apache.nifi.ldap.LdapProvider"
+        def managerPasswordName = "Manager Password"
+        Property managerPasswordProperty = new Property(name: managerPasswordName, value: CIPHER_TEXT, encryption: ENCRYPTION_SCHEME)
+        encryptedProvider.property = [managerPasswordProperty]
+
+        logger.info("Manager Password property: ${managerPasswordProperty.dump()}")
+        def bean = new LoginIdentityProviderFactoryBean()
+
+        // Act
+        def context = bean.loadLoginIdentityProviderConfiguration(encryptedProvider)
+        logger.info("Loaded context: ${context.dump()}")
+
+        // Assert
+        assert context.getProperty(managerPasswordName) == PASSWORD
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
index 30a682c..dc11df4 100644
--- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
@@ -17,6 +17,7 @@
 package org.apache.nifi.properties
 
 import groovy.io.GroovyPrintWriter
+import groovy.xml.XmlUtil
 import org.apache.commons.cli.CommandLine
 import org.apache.commons.cli.CommandLineParser
 import org.apache.commons.cli.DefaultParser
@@ -46,23 +47,30 @@ class ConfigEncryptionTool {
     public String niFiPropertiesPath
     public String outputNiFiPropertiesPath
     public String loginIdentityProvidersPath
+    public String outputLoginIdentityProvidersPath
 
     private String keyHex
     private String migrationKeyHex
     private String password
     private String migrationPassword
+
     private NiFiProperties niFiProperties
+    private String loginIdentityProviders
 
     private boolean usingPassword = true
     private boolean usingPasswordMigration = true
     private boolean migration = false
     private boolean isVerbose = false
+    private boolean handlingNiFiProperties = false
+    private boolean handlingLoginIdentityProviders = false
 
     private static final String HELP_ARG = "help"
     private static final String VERBOSE_ARG = "verbose"
     private static final String BOOTSTRAP_CONF_ARG = "bootstrapConf"
     private static final String NIFI_PROPERTIES_ARG = "niFiProperties"
+    private static final String LOGIN_IDENTITY_PROVIDERS_ARG = "loginIdentityProviders"
     private static final String OUTPUT_NIFI_PROPERTIES_ARG = "outputNiFiProperties"
+    private static final String OUTPUT_LOGIN_IDENTITY_PROVIDERS_ARG = "outputLoginIdentityProviders"
     private static final String KEY_ARG = "key"
     private static final String PASSWORD_ARG = "password"
     private static final String KEY_MIGRATION_ARG = "oldKey"
@@ -87,7 +95,9 @@ class ConfigEncryptionTool {
     private static final String FOOTER = buildFooter()
 
     private static
-    final String DEFAULT_DESCRIPTION = "This tool reads from a nifi.properties file with plain sensitive configuration values, prompts the user for a master key, and encrypts each value. It will replace the plain value with the protected value in the same file (or write to a new nifi.properties file if specified)."
+    final String DEFAULT_DESCRIPTION = "This tool reads from a nifi.properties and/or login-identity-providers.xml file with plain sensitive configuration values, prompts the user for a master key, and encrypts each value. It will replace the plain value with the protected value in the same file (or write to a new file if specified)."
+    static private final String LDAP_PROVIDER_REGEX = /<provider>\s*<identifier>\s*ldap-provider[\s\S]*?<\/provider>/
+    static private final String XML_DECLARATION_REGEX = /<\?xml version="1.0" encoding="UTF-8"\?>/
 
     private static String buildHeader(String description = DEFAULT_DESCRIPTION) {
         "${SEP}${description}${SEP * 2}"
@@ -111,8 +121,10 @@ class ConfigEncryptionTool {
         options.addOption("h", HELP_ARG, false, "Prints this usage message")
         options.addOption("v", VERBOSE_ARG, false, "Sets verbose mode (default false)")
         options.addOption("n", NIFI_PROPERTIES_ARG, true, "The nifi.properties file containing unprotected config values (will be overwritten)")
+        options.addOption("l", LOGIN_IDENTITY_PROVIDERS_ARG, true, "The login-identity-providers.xml file containing unprotected config values (will be overwritten)")
         options.addOption("b", BOOTSTRAP_CONF_ARG, true, "The bootstrap.conf file to persist master key")
         options.addOption("o", OUTPUT_NIFI_PROPERTIES_ARG, true, "The destination nifi.properties file containing protected config values (will not modify input nifi.properties)")
+        options.addOption("i", OUTPUT_LOGIN_IDENTITY_PROVIDERS_ARG, true, "The destination login-identity-providers.xml file containing protected config values (will not modify input login-identity-providers.xml)")
         options.addOption("k", KEY_ARG, true, "The raw hexadecimal key to use to encrypt the sensitive properties")
         options.addOption("e", KEY_MIGRATION_ARG, true, "The old raw hexadecimal key to use during key migration")
         options.addOption("p", PASSWORD_ARG, true, "The password from which to derive the key to use to encrypt the sensitive properties")
@@ -141,6 +153,7 @@ class ConfigEncryptionTool {
         throw new CommandLineParseException(errorMessage, exitCode);
     }
 
+    // TODO: Refactor component steps into methods
     protected CommandLine parse(String[] args) throws CommandLineParseException {
         CommandLineParser parser = new DefaultParser()
         CommandLine commandLine
@@ -152,15 +165,49 @@ class ConfigEncryptionTool {
 
             isVerbose = commandLine.hasOption(VERBOSE_ARG)
 
-            bootstrapConfPath = commandLine.getOptionValue(BOOTSTRAP_CONF_ARG, determineDefaultBootstrapConfPath())
-            niFiPropertiesPath = commandLine.getOptionValue(NIFI_PROPERTIES_ARG, determineDefaultNiFiPropertiesPath())
-            outputNiFiPropertiesPath = commandLine.getOptionValue(OUTPUT_NIFI_PROPERTIES_ARG, niFiPropertiesPath)
+            bootstrapConfPath = commandLine.getOptionValue(BOOTSTRAP_CONF_ARG)
+
+            if (commandLine.hasOption(NIFI_PROPERTIES_ARG)) {
+                if (isVerbose) {
+                    logger.info("Handling encryption of nifi.properties")
+                }
+                niFiPropertiesPath = commandLine.getOptionValue(NIFI_PROPERTIES_ARG)
+                outputNiFiPropertiesPath = commandLine.getOptionValue(OUTPUT_NIFI_PROPERTIES_ARG, niFiPropertiesPath)
+                handlingNiFiProperties = true
 
-            if (niFiPropertiesPath == outputNiFiPropertiesPath) {
-                // TODO: Add confirmation pause and provide -y flag to offer no-interaction mode?
-                logger.warn("The source nifi.properties and destination nifi.properties are identical [${outputNiFiPropertiesPath}] so the original will be overwritten")
+                if (niFiPropertiesPath == outputNiFiPropertiesPath) {
+                    // TODO: Add confirmation pause and provide -y flag to offer no-interaction mode?
+                    logger.warn("The source nifi.properties and destination nifi.properties are identical [${outputNiFiPropertiesPath}] so the original will be overwritten")
+                }
             }
 
+            if (commandLine.hasOption(LOGIN_IDENTITY_PROVIDERS_ARG)) {
+                if (isVerbose) {
+                    logger.info("Handling encryption of login-identity-providers.xml")
+                }
+                loginIdentityProvidersPath = commandLine.getOptionValue(LOGIN_IDENTITY_PROVIDERS_ARG)
+                outputLoginIdentityProvidersPath = commandLine.getOptionValue(OUTPUT_LOGIN_IDENTITY_PROVIDERS_ARG, loginIdentityProvidersPath)
+                handlingLoginIdentityProviders = true
+
+                if (loginIdentityProvidersPath == outputLoginIdentityProvidersPath) {
+                    // TODO: Add confirmation pause and provide -y flag to offer no-interaction mode?
+                    logger.warn("The source login-identity-providers.xml and destination login-identity-providers.xml are identical [${outputLoginIdentityProvidersPath}] so the original will be overwritten")
+                }
+            }
+
+            if (isVerbose) {
+                logger.info("       bootstrap.conf:               \t${bootstrapConfPath}")
+                logger.info("(src)  nifi.properties:              \t${niFiPropertiesPath}")
+                logger.info("(dest) nifi.properties:              \t${outputNiFiPropertiesPath}")
+                logger.info("(src)  login-identity-providers.xml: \t${loginIdentityProvidersPath}")
+                logger.info("(dest) login-identity-providers.xml: \t${outputLoginIdentityProvidersPath}")
+            }
+
+            // TODO: Implement in NIFI-2655
+//            if (!commandLine.hasOption(NIFI_PROPERTIES_ARG) && !commandLine.hasOption(LOGIN_IDENTITY_PROVIDERS_ARG)) {
+//                printUsageAndThrow("One of '-n'/'--${NIFI_PROPERTIES_ARG}' or '-l'/'--${LOGIN_IDENTITY_PROVIDERS_ARG}' must be provided", ExitCode.INVALID_ARGS)
+//            }
+
             if (commandLine.hasOption(MIGRATION_ARG)) {
                 migration = true
                 if (isVerbose) {
@@ -169,7 +216,7 @@ class ConfigEncryptionTool {
                 if (commandLine.hasOption(PASSWORD_MIGRATION_ARG)) {
                     usingPasswordMigration = true
                     if (commandLine.hasOption(KEY_MIGRATION_ARG)) {
-                        printUsageAndThrow("Only one of ${PASSWORD_MIGRATION_ARG} and ${KEY_MIGRATION_ARG} can be used", ExitCode.INVALID_ARGS)
+                        printUsageAndThrow("Only one of '-w'/'--${PASSWORD_MIGRATION_ARG}' and '-e'/'--${KEY_MIGRATION_ARG}' can be used", ExitCode.INVALID_ARGS)
                     } else {
                         migrationPassword = commandLine.getOptionValue(PASSWORD_MIGRATION_ARG)
                     }
@@ -179,14 +226,14 @@ class ConfigEncryptionTool {
                 }
             } else {
                 if (commandLine.hasOption(PASSWORD_MIGRATION_ARG) || commandLine.hasOption(KEY_MIGRATION_ARG)) {
-                    printUsageAndThrow("${PASSWORD_MIGRATION_ARG} and ${KEY_MIGRATION_ARG} are ignored unless ${MIGRATION_ARG} is enabled", ExitCode.INVALID_ARGS)
+                    printUsageAndThrow("'-w'/'--${PASSWORD_MIGRATION_ARG}' and '-e'/'--${KEY_MIGRATION_ARG}' are ignored unless '-m'/'--${MIGRATION_ARG}' is enabled", ExitCode.INVALID_ARGS)
                 }
             }
 
             if (commandLine.hasOption(PASSWORD_ARG)) {
                 usingPassword = true
                 if (commandLine.hasOption(KEY_ARG)) {
-                    printUsageAndThrow("Only one of ${PASSWORD_ARG} and ${KEY_ARG} can be used", ExitCode.INVALID_ARGS)
+                    printUsageAndThrow("Only one of '-p'/'--${PASSWORD_ARG}' and '-k'/'--${KEY_ARG}' can be used", ExitCode.INVALID_ARGS)
                 } else {
                     password = commandLine.getOptionValue(PASSWORD_ARG)
                 }
@@ -311,6 +358,111 @@ class ConfigEncryptionTool {
     }
 
     /**
+     * Loads the login identity providers configuration from the provided file path.
+     *
+     * @param existingKeyHex the key used to encrypt the configs (defaults to the current key)
+     *
+     * @return the file content
+     * @throw IOException if the login-identity-providers.xml file cannot be read
+     */
+    private String loadLoginIdentityProviders(String existingKeyHex = keyHex) throws IOException {
+        File loginIdentityProvidersFile
+        if (loginIdentityProvidersPath && (loginIdentityProvidersFile = new File(loginIdentityProvidersPath)).exists()) {
+            try {
+                String xmlContent = loginIdentityProvidersFile.text
+                List<String> lines = loginIdentityProvidersFile.readLines()
+                logger.info("Loaded LoginIdentityProviders content (${lines.size()} lines)")
+                String decryptedXmlContent = decryptLoginIdentityProviders(xmlContent, existingKeyHex)
+//                String decryptedXmlContent = ConfigEncryptionUtility.decryptLoginIdentityProviders(xmlContent)
+                return decryptedXmlContent
+            } catch (RuntimeException e) {
+                if (isVerbose) {
+                    logger.error("Encountered an error", e)
+                }
+                throw new IOException("Cannot load LoginIdentityProviders from [${loginIdentityProvidersPath}]", e)
+            }
+        } else {
+            printUsageAndThrow("Cannot load LoginIdentityProviders from [${loginIdentityProvidersPath}]", ExitCode.ERROR_READING_NIFI_PROPERTIES)
+        }
+    }
+
+    String decryptLoginIdentityProviders(String encryptedXml, String existingKeyHex = keyHex) {
+        AESSensitivePropertyProvider sensitivePropertyProvider = new AESSensitivePropertyProvider(existingKeyHex)
+
+        try {
+            def doc = new XmlSlurper().parseText(encryptedXml)
+            def passwords = doc.provider.find { it.identifier == 'ldap-provider' }.property.findAll {
+                it.@name =~ "Password" && it.@encryption =~ "aes/gcm/\\d{3}"
+            }
+
+            if (passwords.isEmpty()) {
+                if (isVerbose) {
+                    logger.info("No encrypted password property elements found in login-identity-providers.xml")
+                }
+                return encryptedXml
+            }
+
+            passwords.each { password ->
+                if (isVerbose) {
+                    logger.info("Attempting to decrypt ${password.text()}")
+                }
+                String decryptedValue = sensitivePropertyProvider.unprotect(password.text().trim())
+                password.replaceNode {
+                    property(name: password.@name, encryption: "none", decryptedValue)
+                }
+            }
+
+            // Does not preserve whitespace formatting or comments
+            String updatedXml = XmlUtil.serialize(doc)
+            logger.info("Updated XML content: ${updatedXml}")
+            updatedXml
+        } catch (Exception e) {
+            printUsageAndThrow("Cannot decrypt login identity providers XML content", ExitCode.SERVICE_ERROR)
+        }
+    }
+
+    String encryptLoginIdentityProviders(String plainXml, String newKeyHex = keyHex) {
+        AESSensitivePropertyProvider sensitivePropertyProvider = new AESSensitivePropertyProvider(newKeyHex)
+
+        // TODO: Switch to XmlParser & XmlNodePrinter to maintain "empty" element structure
+        try {
+            def doc = new XmlSlurper().parseText(plainXml)
+            // Only operate on un-encrypted passwords
+            def passwords = doc.provider.find { it.identifier == 'ldap-provider' }
+                    .property.findAll {
+                it.@name =~ "Password" && (it.@encryption == "none" || it.@encryption == "") && it.text()
+            }
+
+            if (passwords.isEmpty()) {
+                if (isVerbose) {
+                    logger.info("No unencrypted password property elements found in login-identity-providers.xml")
+                }
+                return plainXml
+            }
+
+            passwords.each { password ->
+                if (isVerbose) {
+                    logger.info("Attempting to encrypt ${password.name()}")
+                }
+                String encryptedValue = sensitivePropertyProvider.protect(password.text().trim())
+                password.replaceNode {
+                    property(name: password.@name, encryption: sensitivePropertyProvider.identifierKey, encryptedValue)
+                }
+            }
+
+            // Does not preserve whitespace formatting or comments
+            String updatedXml = XmlUtil.serialize(doc)
+            logger.info("Updated XML content: ${updatedXml}")
+            updatedXml
+        } catch (Exception e) {
+            if (isVerbose) {
+                logger.error("Encountered exception", e)
+            }
+            printUsageAndThrow("Cannot encrypt login identity providers XML content", ExitCode.SERVICE_ERROR)
+        }
+    }
+
+    /**
      * Accepts a {@link NiFiProperties} instance, iterates over all non-empty sensitive properties which are not already marked as protected, encrypts them using the master key, and updates the property with the protected value. Additionally, adds a new sibling property {@code x.y.z.protected=aes/gcm/{128,256}} for each indicating the encryption scheme used.
      *
      * @param plainProperties the NiFiProperties instance containing the raw values
@@ -427,6 +579,39 @@ class ConfigEncryptionTool {
     }
 
     /**
+     * Writes the contents of the login identity providers configuration file with encrypted values to the output {@code login-identity-providers.xml} file.
+     *
+     * @throw IOException if there is a problem reading or writing the login-identity-providers.xml file
+     */
+    private void writeLoginIdentityProviders() throws IOException {
+        if (!outputLoginIdentityProvidersPath) {
+            throw new IllegalArgumentException("Cannot write encrypted properties to empty login-identity-providers.xml path")
+        }
+
+        File outputLoginIdentityProvidersFile = new File(outputLoginIdentityProvidersPath)
+
+        if (isSafeToWrite(outputLoginIdentityProvidersFile)) {
+            try {
+                String updatedXmlContent
+                File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+                if (loginIdentityProvidersFile.exists() && loginIdentityProvidersFile.canRead()) {
+                    // Instead of just writing the XML content to a file, this method attempts to maintain the structure of the original file and preserves comments
+                    updatedXmlContent = serializeLoginIdentityProvidersAndPreserveFormat(loginIdentityProviders, loginIdentityProvidersFile).join("\n")
+                }
+
+                // Write the updated values back to the file
+                outputLoginIdentityProvidersFile.text = updatedXmlContent
+            } catch (IOException e) {
+                def msg = "Encountered an exception updating the login-identity-providers.xml file with the encrypted values"
+                logger.error(msg, e)
+                throw e
+            }
+        } else {
+            throw new IOException("The login-identity-providers.xml file at ${outputLoginIdentityProvidersPath} must be writable by the user running this tool")
+        }
+    }
+
+    /**
      * Writes the contents of the {@link NiFiProperties} instance with encrypted values to the output {@code nifi.properties} file.
      *
      * @throw IOException if there is a problem reading or writing the nifi.properties file
@@ -502,6 +687,21 @@ class ConfigEncryptionTool {
         out.toString().split("\n")
     }
 
+
+    private
+    static List<String> serializeLoginIdentityProvidersAndPreserveFormat(String xmlContent, File originalLoginIdentityProvidersFile) {
+       def parsedXml = new XmlSlurper().parseText(xmlContent)
+        def provider = parsedXml.provider.find { it.identifier == "ldap-provider" }
+        def serializedProvider = new XmlUtil().serialize(provider)
+        // Remove XML declaration from top
+        serializedProvider = serializedProvider.replaceFirst(XML_DECLARATION_REGEX, "")
+
+        // Find the provider element of the new XML in the file contents
+        String fileContents = originalLoginIdentityProvidersFile.text
+        fileContents = fileContents.replaceFirst(LDAP_PROVIDER_REGEX, serializedProvider)
+        fileContents.split("\n")
+    }
+
     /**
      * Helper method which returns true if it is "safe" to write to the provided file.
      *
@@ -527,6 +727,11 @@ class ConfigEncryptionTool {
         "${niFiToolkitPath ? niFiToolkitPath + "/" : ""}conf/nifi.properties"
     }
 
+    private static String determineDefaultLoginIdentityProvidersPath() {
+        String niFiToolkitPath = System.getenv(NIFI_TOOLKIT_HOME) ?: ""
+        "${niFiToolkitPath ? niFiToolkitPath + "/" : ""}conf/login-identity-providers.xml"
+    }
+
     private static String deriveKeyFromPassword(String password) {
         password = password?.trim()
         if (!password || password.length() < MIN_PASSWORD_LENGTH) {
@@ -600,12 +805,23 @@ class ConfigEncryptionTool {
                 }
                 String existingKeyHex = tool.migrationKeyHex ?: tool.keyHex
 
-                try {
-                    tool.niFiProperties = tool.loadNiFiProperties(existingKeyHex)
-                } catch (Exception e) {
-                    tool.printUsageAndThrow("Cannot migrate key if no previous encryption occurred", ExitCode.ERROR_READING_NIFI_PROPERTIES)
+                if (tool.handlingNiFiProperties) {
+                    try {
+                        tool.niFiProperties = tool.loadNiFiProperties(existingKeyHex)
+                    } catch (Exception e) {
+                        tool.printUsageAndThrow("Cannot migrate key if no previous encryption occurred", ExitCode.ERROR_READING_NIFI_PROPERTIES)
+                    }
+                    tool.niFiProperties = tool.encryptSensitiveProperties(tool.niFiProperties)
+                }
+
+                if (tool.handlingLoginIdentityProviders) {
+                    try {
+                        tool.loginIdentityProviders = tool.loadLoginIdentityProviders(existingKeyHex)
+                    } catch (Exception e) {
+                        tool.printUsageAndThrow("Cannot migrate key if no previous encryption occurred", ExitCode.ERROR_INCORRECT_NUMBER_OF_PASSWORDS)
+                    }
+                    tool.loginIdentityProviders = tool.encryptLoginIdentityProviders(tool.loginIdentityProviders)
                 }
-                tool.niFiProperties = tool.encryptSensitiveProperties(tool.niFiProperties)
             } catch (CommandLineParseException e) {
                 if (e.exitCode == ExitCode.HELP) {
                     System.exit(ExitCode.HELP.ordinal())
@@ -622,7 +838,12 @@ class ConfigEncryptionTool {
                 // Do this as part of a transaction?
                 synchronized (this) {
                     tool.writeKeyToBootstrapConf()
-                    tool.writeNiFiProperties()
+                    if (tool.handlingNiFiProperties) {
+                        tool.writeNiFiProperties()
+                    }
+                    if (tool.handlingLoginIdentityProviders) {
+                        tool.writeLoginIdentityProviders()
+                    }
                 }
             } catch (Exception e) {
                 if (tool.isVerbose) {


[2/3] nifi git commit: NIFI-2654 Enabled encryption coverage for login-identity-providers.xml.

Posted by ym...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
index c1521d7..1784748 100644
--- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
@@ -25,6 +25,7 @@ import org.apache.nifi.util.console.TextDevice
 import org.apache.nifi.util.console.TextDevices
 import org.bouncycastle.jce.provider.BouncyCastleProvider
 import org.junit.After
+import org.junit.AfterClass
 import org.junit.Assume
 import org.junit.Before
 import org.junit.BeforeClass
@@ -60,10 +61,15 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
     public static final String KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? KEY_HEX_256 : KEY_HEX_128
     private static final String PASSWORD = "thisIsABadPassword"
     // From ConfigEncryptionTool.deriveKeyFromPassword("thisIsABadPassword")
-    private static final String PASSWORD_KEY_HEX_256 = "2C576A9585DB862F5ECBEE5B4FFFCCA14B18D8365968D7081651006507AD2BDE"
+    private static
+    final String PASSWORD_KEY_HEX_256 = "2C576A9585DB862F5ECBEE5B4FFFCCA14B18D8365968D7081651006507AD2BDE"
     private static final String PASSWORD_KEY_HEX_128 = "2C576A9585DB862F5ECBEE5B4FFFCCA1"
 
-    private static final String PASSWORD_KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? PASSWORD_KEY_HEX_256 : PASSWORD_KEY_HEX_128
+    private static
+    final String PASSWORD_KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? PASSWORD_KEY_HEX_256 : PASSWORD_KEY_HEX_128
+
+    private static final int LIP_PASSWORD_LINE_COUNT = 3
+    private final String PASSWORD_PROP_REGEX = "<property[^>]* name=\".* Password\""
 
     @BeforeClass
     public static void setUpOnce() throws Exception {
@@ -72,6 +78,14 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         logger.metaClass.methodMissing = { String name, args ->
             logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
         }
+
+        setupTmpDir()
+    }
+
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+        File tmpDir = new File("target/tmp/")
+        tmpDir.delete()
     }
 
     @Before
@@ -87,6 +101,10 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         Cipher.getMaxAllowedKeyLength("AES") > 128
     }
 
+    private static int getKeyLength(String keyHex = KEY_HEX) {
+        keyHex?.size() * 4
+    }
+
     private static void printProperties(NiFiProperties properties) {
         if (!(properties instanceof ProtectedNiFiProperties)) {
             properties = new ProtectedNiFiProperties(properties)
@@ -139,6 +157,13 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         formattedDate =~ datePattern
     }
 
+    private static File 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
+    }
+
     @Test
     void testShouldPrintHelpMessage() {
         // Arrange
@@ -175,20 +200,6 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
     }
 
     @Test
-    void testParseShouldPopulateDefaultBootstrapConfArgument() {
-        // Arrange
-        String bootstrapPath = "conf/bootstrap.conf"
-        ConfigEncryptionTool tool = new ConfigEncryptionTool()
-
-        // Act
-        tool.parse([] as String[])
-        logger.info("Parsed bootstrap.conf location: ${tool.bootstrapConfPath}")
-
-        // Assert
-        assert new File(tool.bootstrapConfPath).getPath() == new File(bootstrapPath).getPath()
-    }
-
-    @Test
     void testShouldParseNiFiPropertiesArgument() {
         // Arrange
         def flags = ["-n", "--niFiProperties"]
@@ -202,9 +213,12 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
 
             // Assert
             assert tool.niFiPropertiesPath == niFiPropertiesPath
+            assert tool.handlingNiFiProperties
         }
     }
 
+    // TODO: Remove as part of NIFI-2655
+    @Ignore("Remove as part of NIFI-2655")
     @Test
     void testParseShouldPopulateDefaultNiFiPropertiesArgument() {
         // Arrange
@@ -228,7 +242,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
 
         // Act
         flags.each { String arg ->
-            tool.parse([arg, niFiPropertiesPath] as String[])
+            tool.parse([arg, niFiPropertiesPath, "-n", niFiPropertiesPath] as String[])
             logger.info("Parsed output nifi.properties location: ${tool.outputNiFiPropertiesPath}")
 
             // Assert
@@ -236,6 +250,8 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         }
     }
 
+    // TODO: Remove as part of NIFI-2655
+    @Ignore("Remove as part of NIFI-2655")
     @Test
     void testParseShouldPopulateDefaultOutputNiFiPropertiesArgument() {
         // Arrange
@@ -267,6 +283,91 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
     }
 
     @Test
+    void testShouldParseLoginIdentityProvidersArgument() {
+        // Arrange
+        def flags = ["-l", "--loginIdentityProviders"]
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers.xml"
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Act
+        flags.each { String arg ->
+            tool.parse([arg, loginIdentityProvidersPath] as String[])
+            logger.info("Parsed login-identity-providers.xml location: ${tool.loginIdentityProvidersPath}")
+
+            // Assert
+            assert tool.loginIdentityProvidersPath == loginIdentityProvidersPath
+            assert tool.handlingLoginIdentityProviders
+        }
+    }
+
+    // TODO: Remove as part of NIFI-2655
+    @Ignore("Remove as part of NIFI-2655")
+    @Test
+    void testParseShouldPopulateDefaultLoginIdentityProvidersArgument() {
+        // Arrange
+        String loginIdentityProvidersPath = "conf/login-identity-providers.xml"
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Act
+        tool.parse([] as String[])
+        logger.info("Parsed login-identity-providers.xml location: ${tool.loginIdentityProvidersPath}")
+
+        // Assert
+        assert new File(tool.loginIdentityProvidersPath).getPath() == new File(loginIdentityProvidersPath).getPath()
+    }
+
+    @Test
+    void testShouldParseOutputLoginIdentityProvidersArgument() {
+        // Arrange
+        def flags = ["-i", "--outputLoginIdentityProviders"]
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers.xml"
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Act
+        flags.each { String arg ->
+            tool.parse([arg, loginIdentityProvidersPath, "-l", loginIdentityProvidersPath] as String[])
+            logger.info("Parsed output login-identity-providers.xml location: ${tool.outputLoginIdentityProvidersPath}")
+
+            // Assert
+            assert tool.outputLoginIdentityProvidersPath == loginIdentityProvidersPath
+        }
+    }
+
+    // TODO: Remove as part of NIFI-2655
+    @Ignore("Remove as part of NIFI-2655")
+    @Test
+    void testParseShouldPopulateDefaultOutputLoginIdentityProvidersArgument() {
+        // Arrange
+        String loginIdentityProvidersPath = "conf/login-identity-providers.xml"
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Act
+        tool.parse([] as String[])
+        logger.info("Parsed output login-identity-providers.xml location: ${tool.outputLoginIdentityProvidersPath}")
+
+        // Assert
+        assert new File(tool.outputLoginIdentityProvidersPath).getPath() == new File(loginIdentityProvidersPath).getPath()
+    }
+
+    @Test
+    void testParseShouldWarnIfLoginIdentityProvidersWillBeOverwritten() {
+        // Arrange
+        String loginIdentityProvidersPath = "conf/login-identity-providers.xml"
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Act
+        tool.parse("-l ${loginIdentityProvidersPath} -i ${loginIdentityProvidersPath}".split(" ") as String[])
+        logger.info("Parsed login-identity-providers.xml location: ${tool.loginIdentityProvidersPath}")
+        logger.info("Parsed output login-identity-providers.xml location: ${tool.outputLoginIdentityProvidersPath}")
+
+        // Assert
+        assert !TestAppender.events.isEmpty()
+        assert TestAppender.events.any {
+            it.message =~ "The source login-identity-providers.xml and destination login-identity-providers.xml are identical \\[.*\\] so the original will be overwritten"
+        }
+    }
+
+    @Test
     void testShouldParseKeyArgument() {
         // Arrange
         def flags = ["-k", "--key"]
@@ -294,7 +395,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         logger.expected(msg)
 
         // Assert
-        assert msg =~ "Only one of oldPassword and oldKey can be used"
+        assert msg =~ "Only one of '-w'/'--oldPassword' and '-e'/'--oldKey' can be used"
     }
 
     @Test
@@ -307,13 +408,14 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
 
         // Act
         argStrings.each { String argString ->
+            argString += " -n any/path"
             def msg = shouldFail {
                 tool.parse(argString.split(" ") as String[])
             }
             logger.expected(msg)
 
             // Assert
-            assert msg == "oldPassword and oldKey are ignored unless migrate is enabled"
+            assert msg == "'-w'/'--oldPassword' and '-e'/'--oldKey' are ignored unless '-m'/'--migrate' is enabled"
         }
     }
 
@@ -597,7 +699,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
     @Test
     void testShouldHandleKeyAndPasswordFlag() {
         // Arrange
-        def args = ["-k", KEY_HEX, "-p", PASSWORD]
+        def args = ["-k", KEY_HEX, "-p", PASSWORD, "-n", ""]
         logger.info("Using args: ${args}")
 
         // Act
@@ -607,7 +709,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
         logger.expected(msg)
 
         // Assert
-        assert msg == "Only one of password and key can be used"
+        assert msg == "Only one of '-p'/'--password' and '-k'/'--key' can be used"
     }
 
     @Test
@@ -1652,6 +1754,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
 
         exit.checkAssertionAfterwards(new Assertion() {
             public void checkAssertion() {
+                assert outputPropertiesFile.exists()
                 final List<String> updatedPropertiesLines = outputPropertiesFile.readLines()
                 logger.info("Updated nifi.properties:")
                 logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
@@ -1751,6 +1854,627 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
 
         // Assertions in common method above
     }
+
+    @Test
+    void testShouldDecryptLoginIdentityProviders() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-encrypted.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+
+        // Sanity check for decryption
+        String cipherText = "q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA"
+        String EXPECTED_PASSWORD = "thisIsABadPassword"
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX_128)
+        assert spp.unprotect(cipherText) == EXPECTED_PASSWORD
+
+        tool.keyHex = KEY_HEX_128
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        // Act
+        def decryptedLines = tool.decryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Decrypted lines: \n${decryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = decryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { it =~ ">thisIsABadPassword<" }
+        // Some lines were not encrypted originally so the encryption attribute would not have been updated
+        assert passwordLines.any { it =~ "encryption=\"none\"" }
+    }
+
+    @Test
+    void testShouldDecryptLoginIdentityProvidersWithMultilineElements() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-encrypted-multiline.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX_128
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        // Act
+        def decryptedLines = tool.decryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Decrypted lines: \n${decryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = decryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { it =~ ">thisIsABadPassword<" }
+        // Some lines were not encrypted originally so the encryption attribute would not have been updated
+        assert passwordLines.any { it =~ "encryption=\"none\"" }
+    }
+
+    @Test
+    void testShouldDecryptLoginIdentityProvidersWithMultipleElementsPerLine() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-encrypted-multiple-per-line.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX_128
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        // Act
+        def decryptedLines = tool.decryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Decrypted lines: \n${decryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = decryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { it =~ ">thisIsABadPassword<" }
+        // Some lines were not encrypted originally so the encryption attribute would not have been updated
+        assert passwordLines.any { it =~ "encryption=\"none\"" }
+    }
+
+
+    @Test
+    void testDecryptLoginIdentityProvidersShouldHandleCommentedElements() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-commented.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX_128
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        // Act
+        def decryptedLines = tool.decryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Decrypted lines: \n${decryptedLines.join("\n")}")
+
+        // Assert
+
+        // If no encrypted properties are found, the original input text is just returned (comments and formatting in tact)
+        assert decryptedLines == lines
+    }
+
+    @Test
+    void testShouldEncryptLoginIdentityProviders() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX
+        String encryptionScheme = "encryption=\"aes/gcm/${getKeyLength(KEY_HEX)}\""
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        // Act
+        def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Encrypted lines: \n${encryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = encryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { !it.contains(">thisIsABadPassword<") }
+        assert passwordLines.every { it.contains(encryptionScheme) }
+        passwordLines.each {
+            String ct = (it =~ ">(.*)</property>")[0][1]
+            logger.info("Cipher text: ${ct}")
+            assert spp.unprotect(ct) == PASSWORD
+        }
+    }
+
+    @Test
+    void testShouldEncryptLoginIdentityProvidersWithEmptySensitiveElements() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-empty.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX
+        String encryptionScheme = "encryption=\"aes/gcm/${getKeyLength(KEY_HEX)}\""
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        // Act
+        def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Encrypted lines: \n${encryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = encryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        def populatedPasswordLines = passwordLines.findAll { it.contains(">.*<") }
+        assert populatedPasswordLines.every { !it.contains(">thisIsABadPassword<") }
+        assert populatedPasswordLines.every { it.contains(encryptionScheme) }
+        populatedPasswordLines.each {
+            String ct = (it =~ ">(.*)</property>")[0][1]
+            logger.info("Cipher text: ${ct}")
+            assert spp.unprotect(ct) == PASSWORD
+        }
+    }
+
+    @Test
+    void testShouldEncryptLoginIdentityProvidersWithMultilineElements() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-multiline.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX
+        String encryptionScheme = "encryption=\"aes/gcm/${getKeyLength(KEY_HEX)}\""
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        // Act
+        def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Encrypted lines: \n${encryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = encryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { !it.contains(">thisIsABadPassword<") }
+        assert passwordLines.every { it.contains(encryptionScheme) }
+        passwordLines.each {
+            String ct = (it =~ ">(.*)</property>")[0][1]
+            logger.info("Cipher text: ${ct}")
+            assert spp.unprotect(ct) == PASSWORD
+        }
+    }
+
+    @Test
+    void testShouldEncryptLoginIdentityProvidersWithMultipleElementsPerLine() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated-multiple-per-line.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX
+        String encryptionScheme = "encryption=\"aes/gcm/${getKeyLength(KEY_HEX)}\""
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        // Act
+        def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Encrypted lines: \n${encryptedLines.join("\n")}")
+
+        // Assert
+        def passwordLines = encryptedLines.findAll { it =~ PASSWORD_PROP_REGEX }
+        assert passwordLines.size() == LIP_PASSWORD_LINE_COUNT
+        assert passwordLines.every { !it.contains(">thisIsABadPassword<") }
+        assert passwordLines.every { it.contains(encryptionScheme) }
+        passwordLines.each {
+            String ct = (it =~ ">(.*)</property>")[0][1]
+            logger.info("Cipher text: ${ct}")
+            assert spp.unprotect(ct) == PASSWORD
+        }
+    }
+
+    @Test
+    void testEncryptLoginIdentityProvidersShouldHandleCommentedElements() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-commented.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        tool.keyHex = KEY_HEX_128
+
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        // Act
+        def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n")
+        logger.info("Encrypted lines: \n${encryptedLines.join("\n")}")
+
+        // Assert
+
+        // If no sensitive properties are found, the original input text is just returned (comments and formatting in tact)
+        assert encryptedLines == lines
+    }
+
+    @Test
+    void testShouldPerformFullOperationForLoginIdentityProviders() {
+        // Arrange
+        exit.expectSystemExitWithStatus(0)
+
+        File tmpDir = setupTmpDir()
+
+        File emptyKeyFile = new File("src/test/resources/bootstrap_with_empty_master_key.conf")
+        File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
+        bootstrapFile.delete()
+
+        Files.copy(emptyKeyFile.toPath(), bootstrapFile.toPath())
+        final List<String> originalBootstrapLines = bootstrapFile.readLines()
+        String originalKeyLine = originalBootstrapLines.find {
+            it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+        }
+        logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
+        assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
+
+        final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + KEY_HEX
+
+        File inputLIPFile = new File("src/test/resources/login-identity-providers-populated.xml")
+        File outputLIPFile = new File("target/tmp/tmp-lip.xml")
+        outputLIPFile.delete()
+
+        String originalXmlContent = inputLIPFile.text
+        logger.info("Original XML content: ${originalXmlContent}")
+
+        String[] args = ["-l", inputLIPFile.path, "-b", bootstrapFile.path, "-i", outputLIPFile.path, "-k", KEY_HEX, "-v"]
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        exit.checkAssertionAfterwards(new Assertion() {
+            public void checkAssertion() {
+                final String updatedXmlContent = outputLIPFile.text
+                logger.info("Updated XML content: ${updatedXmlContent}")
+
+                // Check that the output values for sensitive properties are not the same as the original (i.e. it was encrypted)
+                def originalParsedXml = new XmlSlurper().parseText(originalXmlContent)
+                def updatedParsedXml = new XmlSlurper().parseText(updatedXmlContent)
+                assert originalParsedXml != updatedParsedXml
+                assert originalParsedXml.'**'.findAll { it.@encryption } != updatedParsedXml.'**'.findAll {
+                    it.@encryption
+                }
+
+                def encryptedValues = updatedParsedXml.provider.find {
+                    it.identifier == 'ldap-provider'
+                }.property.findAll {
+                    it.@name =~ "Password" && it.@encryption =~ "aes/gcm/\\d{3}"
+                }
+
+                encryptedValues.each {
+                    assert spp.unprotect(it.text()) == PASSWORD
+                }
+
+                // Check that the key was persisted to the bootstrap.conf
+                final List<String> updatedBootstrapLines = bootstrapFile.readLines()
+                String updatedKeyLine = updatedBootstrapLines.find {
+                    it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+                }
+                logger.info("Updated key line: ${updatedKeyLine}")
+
+                assert updatedKeyLine == EXPECTED_KEY_LINE
+                assert originalBootstrapLines.size() == updatedBootstrapLines.size()
+
+                // Clean up
+                outputLIPFile.deleteOnExit()
+                bootstrapFile.deleteOnExit()
+                tmpDir.deleteOnExit()
+            }
+        });
+
+        // Act
+        ConfigEncryptionTool.main(args)
+        logger.info("Invoked #main with ${args.join(" ")}")
+
+        // Assert
+
+        // Assertions defined above
+    }
+
+    @Test
+    void testShouldPerformFullOperationMigratingLoginIdentityProviders() {
+        // Arrange
+        exit.expectSystemExitWithStatus(0)
+
+        File tmpDir = setupTmpDir()
+
+        // Start with 128-bit encryption and go to whatever is supported on this system
+        File emptyKeyFile = new File("src/test/resources/bootstrap_with_master_key_128.conf")
+        File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
+        bootstrapFile.delete()
+
+        Files.copy(emptyKeyFile.toPath(), bootstrapFile.toPath())
+        final List<String> originalBootstrapLines = bootstrapFile.readLines()
+        String originalKeyLine = originalBootstrapLines.find {
+            it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+        }
+        logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
+        assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + KEY_HEX_128
+
+        final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX
+
+        File inputLIPFile = new File("src/test/resources/login-identity-providers-populated-encrypted.xml")
+        File outputLIPFile = new File("target/tmp/tmp-lip.xml")
+        outputLIPFile.delete()
+
+        String originalXmlContent = inputLIPFile.text
+        logger.info("Original XML content: ${originalXmlContent}")
+
+        // Migrate from KEY_HEX_128 to PASSWORD_KEY_HEX
+        String[] args = ["-l", inputLIPFile.path, "-b", bootstrapFile.path, "-i", outputLIPFile.path, "-m", "-e", KEY_HEX_128, "-k", PASSWORD_KEY_HEX, "-v"]
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(PASSWORD_KEY_HEX)
+
+        exit.checkAssertionAfterwards(new Assertion() {
+            public void checkAssertion() {
+                final String updatedXmlContent = outputLIPFile.text
+                logger.info("Updated XML content: ${updatedXmlContent}")
+
+                // Check that the output values for sensitive properties are not the same as the original (i.e. it was encrypted)
+                def originalParsedXml = new XmlSlurper().parseText(originalXmlContent)
+                def updatedParsedXml = new XmlSlurper().parseText(updatedXmlContent)
+                assert originalParsedXml != updatedParsedXml
+//                assert originalParsedXml.'**'.findAll { it.@encryption } != updatedParsedXml.'**'.findAll { it.@encryption }
+
+                def encryptedValues = updatedParsedXml.provider.find {
+                    it.identifier == 'ldap-provider'
+                }.property.findAll {
+                    it.@name =~ "Password" && it.@encryption =~ "aes/gcm/\\d{3}"
+                }
+
+                encryptedValues.each {
+                    assert spp.unprotect(it.text()) == PASSWORD
+                }
+
+                // Check that the key was persisted to the bootstrap.conf
+                final List<String> updatedBootstrapLines = bootstrapFile.readLines()
+                String updatedKeyLine = updatedBootstrapLines.find {
+                    it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+                }
+                logger.info("Updated key line: ${updatedKeyLine}")
+
+                assert updatedKeyLine == EXPECTED_KEY_LINE
+                assert originalBootstrapLines.size() == updatedBootstrapLines.size()
+
+                // Clean up
+                outputLIPFile.deleteOnExit()
+                bootstrapFile.deleteOnExit()
+                tmpDir.deleteOnExit()
+            }
+        });
+
+        // Act
+        ConfigEncryptionTool.main(args)
+        logger.info("Invoked #main with ${args.join(" ")}")
+
+        // Assert
+
+        // Assertions defined above
+    }
+
+    @Test
+    void testSerializeLoginIdentityProvidersAndPreserveFormatShouldRespectComments() {
+        // Arrange
+        String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-populated.xml"
+        File loginIdentityProvidersFile = new File(loginIdentityProvidersPath)
+
+        File tmpDir = setupTmpDir()
+
+        File workingFile = new File("target/tmp/tmp-login-identity-providers.xml")
+        workingFile.delete()
+        Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath())
+        ConfigEncryptionTool tool = new ConfigEncryptionTool()
+        tool.isVerbose = true
+
+        // Just need to read the lines from the original file, parse them to XML, serialize back, and compare output, as no transformation operation will occur
+        def lines = workingFile.readLines()
+        logger.info("Read lines: \n${lines.join("\n")}")
+
+        String plainXml = workingFile.text
+        String encryptedXml = tool.encryptLoginIdentityProviders(plainXml, KEY_HEX)
+        logger.info("Encrypted XML: \n${encryptedXml}")
+
+        // Act
+        def serializedLines = tool.serializeLoginIdentityProvidersAndPreserveFormat(encryptedXml, workingFile)
+        logger.info("Serialized lines: \n${serializedLines.join("\n")}")
+
+        // Assert
+
+        // Some empty lines will be removed
+        def trimmedLines = lines.collect {it.trim() }.findAll { it }
+        def trimmedSerializedLines = serializedLines.collect { it.trim() }.findAll { it }
+        assert trimmedLines.size() == trimmedSerializedLines.size()
+    }
+
+    @Test
+    void testShouldPerformFullOperationForNiFiPropertiesAndLoginIdentityProviders() {
+        // Arrange
+        exit.expectSystemExitWithStatus(0)
+
+        File tmpDir = setupTmpDir()
+
+        File emptyKeyFile = new File("src/test/resources/bootstrap_with_empty_master_key.conf")
+        File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
+        bootstrapFile.delete()
+
+        Files.copy(emptyKeyFile.toPath(), bootstrapFile.toPath())
+        final List<String> originalBootstrapLines = bootstrapFile.readLines()
+        String originalKeyLine = originalBootstrapLines.find {
+            it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+        }
+        logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
+        assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
+
+        final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + KEY_HEX
+
+        // Set up the NFP file
+        File inputPropertiesFile = new File("src/test/resources/nifi_with_sensitive_properties_unprotected.properties")
+        File outputPropertiesFile = new File("target/tmp/tmp_nifi.properties")
+        outputPropertiesFile.delete()
+
+        NiFiProperties inputProperties = new NiFiPropertiesLoader().load(inputPropertiesFile)
+        logger.info("Loaded ${inputProperties.size()} properties from input file")
+        ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
+        def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
+        logger.info("Original sensitive values: ${originalSensitiveValues}")
+
+        // Set up the LIP file
+        File inputLIPFile = new File("src/test/resources/login-identity-providers-populated.xml")
+        File outputLIPFile = new File("target/tmp/tmp-lip.xml")
+        outputLIPFile.delete()
+
+        String originalXmlContent = inputLIPFile.text
+        logger.info("Original XML content: ${originalXmlContent}")
+
+        String[] args = ["-n", inputPropertiesFile.path, "-l", inputLIPFile.path, "-b", bootstrapFile.path, "-i", outputLIPFile.path, "-o", outputPropertiesFile.path, "-k", KEY_HEX, "-v"]
+
+        AESSensitivePropertyProvider spp = new AESSensitivePropertyProvider(KEY_HEX)
+
+        exit.checkAssertionAfterwards(new Assertion() {
+            public void checkAssertion() {
+                final List<String> updatedPropertiesLines = outputPropertiesFile.readLines()
+                logger.info("Updated nifi.properties:")
+                logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
+
+                // Check that the output values for sensitive properties are not the same as the original (i.e. it was encrypted)
+                NiFiProperties updatedProperties = new NiFiPropertiesLoader().readProtectedPropertiesFromDisk(outputPropertiesFile)
+                assert updatedProperties.size() >= inputProperties.size()
+                originalSensitiveValues.every { String key, String originalValue ->
+                    assert updatedProperties.getProperty(key) != originalValue
+                }
+
+                // Check that the new NiFiProperties instance matches the output file (values still encrypted)
+                updatedProperties.getPropertyKeys().every { String key ->
+                    assert updatedPropertiesLines.contains("${key}=${updatedProperties.getProperty(key)}".toString())
+                }
+
+                final String updatedXmlContent = outputLIPFile.text
+                logger.info("Updated XML content: ${updatedXmlContent}")
+
+                // Check that the output values for sensitive properties are not the same as the original (i.e. it was encrypted)
+                def originalParsedXml = new XmlSlurper().parseText(originalXmlContent)
+                def updatedParsedXml = new XmlSlurper().parseText(updatedXmlContent)
+                assert originalParsedXml != updatedParsedXml
+                assert originalParsedXml.'**'.findAll { it.@encryption } != updatedParsedXml.'**'.findAll {
+                    it.@encryption
+                }
+
+                def encryptedValues = updatedParsedXml.provider.find {
+                    it.identifier == 'ldap-provider'
+                }.property.findAll {
+                    it.@name =~ "Password" && it.@encryption =~ "aes/gcm/\\d{3}"
+                }
+
+                encryptedValues.each {
+                    assert spp.unprotect(it.text()) == PASSWORD
+                }
+
+                // Check that the comments are still there
+                def trimmedLines = inputLIPFile.readLines().collect {it.trim() }.findAll { it }
+                def trimmedSerializedLines = updatedXmlContent.split("\n").collect { it.trim() }.findAll { it }
+                assert trimmedLines.size() == trimmedSerializedLines.size()
+
+                // Check that the key was persisted to the bootstrap.conf
+                final List<String> updatedBootstrapLines = bootstrapFile.readLines()
+                String updatedKeyLine = updatedBootstrapLines.find {
+                    it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+                }
+                logger.info("Updated key line: ${updatedKeyLine}")
+
+                assert updatedKeyLine == EXPECTED_KEY_LINE
+                assert originalBootstrapLines.size() == updatedBootstrapLines.size()
+
+                // Clean up
+                outputPropertiesFile.deleteOnExit()
+                outputLIPFile.deleteOnExit()
+                bootstrapFile.deleteOnExit()
+                tmpDir.deleteOnExit()
+            }
+        });
+
+        // Act
+        ConfigEncryptionTool.main(args)
+        logger.info("Invoked #main with ${args.join(" ")}")
+
+        // Assert
+
+        // Assertions defined above
+    }
 }
 
 public class TestAppender extends AppenderBase<LoggingEvent> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/bootstrap_with_master_key_128.conf
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/bootstrap_with_master_key_128.conf b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/bootstrap_with_master_key_128.conf
new file mode 100644
index 0000000..ae994de
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/bootstrap_with_master_key_128.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=-Xms512m
+java.arg.3=-Xmx512m
+
+# 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=0123456789ABCDEFFEDCBA9876543210
+
+###
+# 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
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented-populated.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented-populated.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented-populated.xml
new file mode 100644
index 0000000..53f5736
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented-populated.xml
@@ -0,0 +1,107 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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">thisIsABadPassword</property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password">thisIsABadPassword</property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented.xml
new file mode 100644
index 0000000..a2beb4c
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-commented.xml
@@ -0,0 +1,107 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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="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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-empty.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-empty.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-empty.xml
new file mode 100644
index 0000000..2a0917d
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-empty.xml
@@ -0,0 +1,105 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiline.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiline.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiline.xml
new file mode 100644
index 0000000..8c5ade5
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiline.xml
@@ -0,0 +1,110 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password" encryption=
+                "aes/gcm/128">q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA</property>
+
+        <property name="TLS - Keystore"></property>
+        <property
+                name="TLS - Keystore Password"
+                encryption="aes/gcm/128">
+            Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g
+        </property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiple-per-line.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiple-per-line.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiple-per-line.xml
new file mode 100644
index 0000000..e551035
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted-multiple-per-line.xml
@@ -0,0 +1,101 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password" encryption="aes/gcm/128">q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA</property><property name="TLS - Keystore"></property><property name="TLS - Keystore Password" encryption="aes/gcm/128">Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g</property><property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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/59fea1cb/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted.xml
----------------------------------------------------------------------
diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted.xml
new file mode 100644
index 0000000..705eb88
--- /dev/null
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/login-identity-providers-populated-encrypted.xml
@@ -0,0 +1,105 @@
+<?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, 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 START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using 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' - Url of the LDAP servier (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}'.
+            
+        '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.
+    -->
+    <provider>
+        <identifier>ldap-provider</identifier>
+        <class>org.apache.nifi.ldap.LdapProvider</class>
+        <property name="Authentication Strategy">START_TLS</property>
+
+        <property name="Manager DN">someuser</property>
+        <property name="Manager Password" encryption="aes/gcm/128">q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA</property>
+
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password" encryption="aes/gcm/128">Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g</property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password">thisIsABadPassword</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="Authentication Expiration">12 hours</property>
+    </provider>
+
+    <!--
+        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