You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/09/22 02:11:21 UTC

[22/51] [partial] nifi-registry git commit: NIFIREG-201 Refactoring project structure to better isolate extensions

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/run-nifi-registry.bat
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/run-nifi-registry.bat b/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/run-nifi-registry.bat
new file mode 100644
index 0000000..c8d6541
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/run-nifi-registry.bat
@@ -0,0 +1,50 @@
+@echo off
+rem
+rem    Licensed to the Apache Software Foundation (ASF) under one or more
+rem    contributor license agreements.  See the NOTICE file distributed with
+rem    this work for additional information regarding copyright ownership.
+rem    The ASF licenses this file to You under the Apache License, Version 2.0
+rem    (the "License"); you may not use this file except in compliance with
+rem    the License.  You may obtain a copy of the License at
+rem
+rem       http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem    Unless required by applicable law or agreed to in writing, software
+rem    distributed under the License is distributed on an "AS IS" BASIS,
+rem    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem    See the License for the specific language governing permissions and
+rem    limitations under the License.
+rem
+
+rem Use JAVA_HOME if it's set; otherwise, just use java
+
+if "%JAVA_HOME%" == "" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+goto startNiFiRegistry
+
+:noJavaHome
+echo The JAVA_HOME environment variable is not defined correctly.
+echo Instead the PATH will be used to find the java executable.
+echo.
+set JAVA_EXE=java
+goto startNiFiRegistry
+
+:startNiFiRegistry
+set NIFI_REGISTRY_ROOT=%~dp0..
+pushd "%NIFI_REGISTRY_ROOT%\"
+set LIB_DIR=%NIFI_REGISTRY_ROOT%\lib
+set SHARED_DIR=%NIFI_REGISTRY_ROOT%\lib\shared
+set BOOTSTRAP_DIR=%NIFI_REGISTRY_ROOT%\lib\bootstrap
+set CONF_DIR=%NIFI_REGISTRY_ROOT%\conf
+
+set BOOTSTRAP_CONF_FILE=%CONF_DIR%\bootstrap.conf
+set JAVA_ARGS=-Dorg.apache.nifi.registry.bootstrap.config.file=%BOOTSTRAP_CONF_FILE%
+
+SET JAVA_PARAMS=-cp %CONF_DIR%;%LIB_DIR%\*;%SHARED_DIR%\*;%BOOTSTRAP_DIR%\* -Xms512m -Xmx1024m %JAVA_ARGS% org.apache.nifi.registry.NiFiRegistry
+set BOOTSTRAP_ACTION=run
+
+echo cmd.exe /C "%JAVA_EXE%" %JAVA_PARAMS% %BOOTSTRAP_ACTION%
+cmd.exe /C "%JAVA_EXE%" %JAVA_PARAMS% %BOOTSTRAP_ACTION%
+
+popd

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/status-nifi-registry.bat
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/status-nifi-registry.bat b/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/status-nifi-registry.bat
new file mode 100644
index 0000000..30a29a0
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/bin/status-nifi-registry.bat
@@ -0,0 +1,49 @@
+@echo off
+rem
+rem    Licensed to the Apache Software Foundation (ASF) under one or more
+rem    contributor license agreements.  See the NOTICE file distributed with
+rem    this work for additional information regarding copyright ownership.
+rem    The ASF licenses this file to You under the Apache License, Version 2.0
+rem    (the "License"); you may not use this file except in compliance with
+rem    the License.  You may obtain a copy of the License at
+rem
+rem       http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem    Unless required by applicable law or agreed to in writing, software
+rem    distributed under the License is distributed on an "AS IS" BASIS,
+rem    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem    See the License for the specific language governing permissions and
+rem    limitations under the License.
+rem
+
+rem Use JAVA_HOME if it's set; otherwise, just use java
+
+if "%JAVA_HOME%" == "" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+goto startNiFiRegistry
+
+:noJavaHome
+echo The JAVA_HOME environment variable is not defined correctly.
+echo Instead the PATH will be used to find the java executable.
+echo.
+set JAVA_EXE=java
+goto startNiFiRegistry
+
+:startNiFiRegistry
+set NIFI_REGISTRY_ROOT=%~dp0..\
+pushd "%NIFI_REGISTRY_ROOT%"
+set LIB_DIR=%NIFI_REGISTRY_ROOT%\lib
+set SHARED_DIR=%NIFI_REGISTRY_ROOT%\lib\shared
+set BOOTSTRAP_DIR=%NIFI_REGISTRY_ROOT%\lib\bootstrap
+set CONF_DIR=conf
+
+set BOOTSTRAP_CONF_FILE=%CONF_DIR%\bootstrap.conf
+set JAVA_ARGS=-Dorg.apache.nifi.registry.bootstrap.config.file=%BOOTSTRAP_CONF_FILE%
+
+set JAVA_PARAMS=-cp %LIB_DIR%\*;%SHARED_DIR%\*;%BOOTSTRAP_DIR%\* -Xms12m -Xmx24m %JAVA_ARGS% org.apache.nifi.registry.NiFiRegistry
+set BOOTSTRAP_ACTION=status
+
+cmd.exe /C "%JAVA_EXE%" %JAVA_PARAMS% %BOOTSTRAP_ACTION%
+
+popd

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/authorizers.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/authorizers.xml b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/authorizers.xml
new file mode 100644
index 0000000..772db61
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/authorizers.xml
@@ -0,0 +1,256 @@
+<?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 userGroupProviders, accessPolicyProviders, and authorizers to use when running securely. In order
+    to use a specific authorizer it must be configured here and its identifier must be specified in the nifi-registry.properties file.
+    If the authorizer is a managedAuthorizer, it may need to be configured with an accessPolicyProvider and an userGroupProvider.
+    This file allows for configuration of them, but they must be configured in order:
+
+    ...
+    all userGroupProviders
+    all accessPolicyProviders
+    all Authorizers
+    ...
+-->
+<authorizers>
+
+    <!--
+        The FileUserGroupProvider will provide support for managing users and groups which is backed by a file
+        on the local file system.
+
+        - Users File - The file where the FileUserGroupProvider will store users and groups.
+
+        - Initial User Identity [unique key] - The identity of a users and systems to seed the Users File. The name of
+            each property must be unique, for example: "Initial User Identity A", "Initial User Identity B",
+            "Initial User Identity C" or "Initial User Identity 1", "Initial User Identity 2", "Initial User Identity 3"
+
+            NOTE: Any identity mapping rules specified in nifi-registry.properties will also be applied to the user identities,
+            so the values should be the unmapped identities (i.e. full DN from a certificate).
+    -->
+    <userGroupProvider>
+        <identifier>file-user-group-provider</identifier>
+        <class>org.apache.nifi.registry.security.authorization.file.FileUserGroupProvider</class>
+        <property name="Users File">./conf/users.xml</property>
+        <property name="Initial User Identity 1"><!--CN=abc, OU=xyz--></property>
+    </userGroupProvider>
+
+    <!--
+        The LdapUserGroupProvider will retrieve users and groups from an LDAP server. The users and groups
+        are not configurable.
+
+        'Authentication Strategy' - How the connection to the LDAP server is authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP server to search for users.
+        'Manager Password' - The password of the manager that is used to bind to the LDAP server to
+            search for users.
+
+        'TLS - Keystore' - Path to the Keystore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut down gracefully
+            before the target context is closed. Defaults to false.
+
+        'Referral Strategy' - Strategy for handling referrals. Possible values are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. ldap://<hostname>:<port>).
+        'Page Size' - Sets the page size when retrieving users and groups. If not specified, no paging is performed.
+        'Sync Interval' - Duration of time between syncing users and groups. (i.e. 30 mins).
+
+        'User Search Base' - Base DN for searching for users (i.e. ou=users,o=nifi). Required to search users.
+        'User Object Class' - Object class for identifying users (i.e. person). Required if searching users.
+        'User Search Scope' - Search scope for searching users (ONE_LEVEL, OBJECT, or SUBTREE). Required if searching users.
+        'User Search Filter' - Filter for searching for users against the 'User Search Base' (i.e. (memberof=cn=team1,ou=groups,o=nifi) ). Optional.
+        'User Identity Attribute' - Attribute to use to extract user identity (i.e. cn). Optional. If not set, the entire DN is used.
+        'User Group Name Attribute' - Attribute to use to define group membership (i.e. memberof). Optional. If not set
+            group membership will not be calculated through the users. Will rely on group membership being defined
+            through 'Group Member Attribute' if set. The value of this property is the name of the attribute in the user ldap entry that
+            associates them with a group. The value of that user attribute could be a dn or group name for instance. What value is expected
+            is configured in the 'User Group Name Attribute - Referenced Group Attribute'.
+        'User Group Name Attribute - Referenced Group Attribute' - If blank, the value of the attribute defined in 'User Group Name Attribute'
+            is expected to be the full dn of the group. If not blank, this property will define the attribute of the group ldap entry that
+            the value of the attribute defined in 'User Group Name Attribute' is referencing (i.e. name). Use of this property requires that
+            'Group Search Base' is also configured.
+
+        'Group Search Base' - Base DN for searching for groups (i.e. ou=groups,o=nifi). Required to search groups.
+        'Group Object Class' - Object class for identifying groups (i.e. groupOfNames). Required if searching groups.
+        'Group Search Scope' - Search scope for searching groups (ONE_LEVEL, OBJECT, or SUBTREE). Required if searching groups.
+        'Group Search Filter' - Filter for searching for groups against the 'Group Search Base'. Optional.
+        'Group Name Attribute' - Attribute to use to extract group name (i.e. cn). Optional. If not set, the entire DN is used.
+        'Group Member Attribute' - Attribute to use to define group membership (i.e. member). Optional. If not set
+            group membership will not be calculated through the groups. Will rely on group membership being defined
+            through 'User Group Name Attribute' if set. The value of this property is the name of the attribute in the group ldap entry that
+            associates them with a user. The value of that group attribute could be a dn or memberUid for instance. What value is expected
+            is configured in the 'Group Member Attribute - Referenced User Attribute'. (i.e. member: cn=User 1,ou=users,o=nifi-registry vs. memberUid: user1)
+        'Group Member Attribute - Referenced User Attribute' - If blank, the value of the attribute defined in 'Group Member Attribute'
+            is expected to be the full dn of the user. If not blank, this property will define the attribute of the user ldap entry that
+            the value of the attribute defined in 'Group Member Attribute' is referencing (i.e. uid). Use of this property requires that
+            'User Search Base' is also configured. (i.e. member: cn=User 1,ou=users,o=nifi-registry vs. memberUid: user1)
+
+        NOTE: Any identity mapping rules specified in nifi-registry.properties will also be applied to the user identities.
+            Group names are not mapped.
+    -->
+    <!-- To enable the ldap-user-group-provider remove 2 lines. This is 1 of 2.
+    <userGroupProvider>
+        <identifier>ldap-user-group-provider</identifier>
+        <class>org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider</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="Page Size"></property>
+        <property name="Sync Interval">30 mins</property>
+
+        <property name="User Search Base"></property>
+        <property name="User Object Class">person</property>
+        <property name="User Search Scope">ONE_LEVEL</property>
+        <property name="User Search Filter"></property>
+        <property name="User Identity Attribute"></property>
+        <property name="User Group Name Attribute"></property>
+        <property name="User Group Name Attribute - Referenced Group Attribute"></property>
+
+        <property name="Group Search Base"></property>
+        <property name="Group Object Class">group</property>
+        <property name="Group Search Scope">ONE_LEVEL</property>
+        <property name="Group Search Filter"></property>
+        <property name="Group Name Attribute"></property>
+        <property name="Group Member Attribute"></property>
+        <property name="Group Member Attribute - Referenced User Attribute"></property>
+    </userGroupProvider>
+    To enable the ldap-user-group-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        The CompositeUserGroupProvider will provide support for retrieving users and groups from multiple sources.
+
+        - User Group Provider [unique key] - The identifier of user group providers to load from. The name of
+            each property must be unique, for example: "User Group Provider A", "User Group Provider B",
+            "User Group Provider C" or "User Group Provider 1", "User Group Provider 2", "User Group Provider 3"
+
+            NOTE: Any identity mapping rules specified in nifi-registry.properties are not applied in this implementation. This
+            behavior would need to be applied by the base implementation.
+    -->
+    <!-- To enable the composite-user-group-provider remove 2 lines. This is 1 of 2.
+    <userGroupProvider>
+        <identifier>composite-user-group-provider</identifier>
+        <class>org.apache.nifi.registry.security.authorization.CompositeUserGroupProvider</class>
+        <property name="User Group Provider 1"></property>
+    </userGroupProvider>
+    To enable the composite-user-group-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        The CompositeConfigurableUserGroupProvider will provide support for retrieving users and groups from multiple sources.
+        Additionally, a single configurable user group provider is required. Users from the configurable user group provider
+        are configurable, however users loaded from one of the User Group Provider [unique key] will not be.
+
+        - Configurable User Group Provider - A configurable user group provider.
+
+        - User Group Provider [unique key] - The identifier of user group providers to load from. The name of
+            each property must be unique, for example: "User Group Provider A", "User Group Provider B",
+            "User Group Provider C" or "User Group Provider 1", "User Group Provider 2", "User Group Provider 3"
+
+            NOTE: Any identity mapping rules specified in nifi-registry.properties are not applied in this implementation. This
+            behavior would need to be applied by the base implementation.
+    -->
+    <!-- To enable the composite-configurable-user-group-provider remove 2 lines. This is 1 of 2.
+    <userGroupProvider>
+        <identifier>composite-configurable-user-group-provider</identifier>
+        <class>org.apache.nifi.registry.security.authorization.CompositeConfigurableUserGroupProvider</class>
+        <property name="Configurable User Group Provider">file-user-group-provider</property>
+        <property name="User Group Provider 1"></property>
+    </userGroupProvider>
+    To enable the composite-configurable-user-group-provider remove 2 lines. This is 2 of 2. -->
+
+    <!--
+        The FileAccessPolicyProvider will provide support for managing access policies which is backed by a file
+        on the local file system.
+
+        - User Group Provider - The identifier for an User Group Provider defined above that will be used to access
+            users and groups for use in the managed access policies.
+
+        - Authorizations File - The file where the FileAccessPolicyProvider will store policies.
+
+        - Initial Admin Identity - The identity of an initial admin user that will be granted access to the UI and
+            given the ability to create additional users, groups, and policies. The value of this property could be
+            a DN when using certificates or LDAP. This property will only be used when there
+            are no other policies defined.
+
+            NOTE: Any identity mapping rules specified in nifi-registry.properties will also be applied to the initial admin identity,
+            so the value should be the unmapped identity. This identity must be found in the configured User Group Provider.
+
+        - NiFi Identity [unique key] - The identity of a NiFi node that will have access to this NiFi Registry and will be able
+            to act as a proxy on behalf of a NiFi Registry end user. A property should be created for the identity of every NiFi
+            node that needs to access this NiFi Registry. The name of each property must be unique, for example for three
+            NiFi clients:
+            "NiFi Identity A", "NiFi Identity B", "NiFi Identity C" or "NiFi Identity 1", "NiFi Identity 2", "NiFi Identity 3"
+
+            NOTE: Any identity mapping rules specified in nifi-registry.properties will also be applied to the nifi identities,
+            so the values should be the unmapped identities (i.e. full DN from a certificate). This identity must be found
+            in the configured User Group Provider.
+    -->
+    <accessPolicyProvider>
+        <identifier>file-access-policy-provider</identifier>
+        <class>org.apache.nifi.registry.security.authorization.file.FileAccessPolicyProvider</class>
+        <property name="User Group Provider">file-user-group-provider</property>
+        <property name="Authorizations File">./conf/authorizations.xml</property>
+        <property name="Initial Admin Identity"><!-- CN=abc, OU=xyz --></property>
+
+        <!--<property name="NiFi Identity 1"></property>-->
+    </accessPolicyProvider>
+
+    <!--
+        The StandardManagedAuthorizer. This authorizer implementation must be configured with the
+        Access Policy Provider which it will use to access and manage users, groups, and policies.
+        These users, groups, and policies will be used to make all access decisions during authorization
+        requests.
+
+        - Access Policy Provider - The identifier for an Access Policy Provider defined above.
+    -->
+    <authorizer>
+        <identifier>managed-authorizer</identifier>
+        <class>org.apache.nifi.registry.security.authorization.StandardManagedAuthorizer</class>
+        <property name="Access Policy Provider">file-access-policy-provider</property>
+    </authorizer>
+
+</authorizers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
new file mode 100644
index 0000000..637eb64
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
@@ -0,0 +1,48 @@
+#
+# 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-registry
+java=java
+
+# Username to use when running nifi-registry. This value will be ignored on Windows.
+run.as=
+
+# Configure where nifi-registry's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling nifi-registry 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
+
+# Master key in hexadecimal format for encrypted sensitive configuration values
+nifi.registry.bootstrap.sensitive.key=
\ No newline at end of file

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

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/logback.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/logback.xml b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/logback.xml
new file mode 100644
index 0000000..7d65bda
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/logback.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<configuration scan="true" scanPeriod="30 seconds">
+    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+        <resetJUL>true</resetJUL>
+    </contextListener>
+    
+    <appender name="APP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>logs/nifi-registry-app.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!--
+              For daily rollover, use 'app_%d.log'.
+              For hourly rollover, use 'app_%d{yyyy-MM-dd_HH}.log'.
+              To GZIP rolled files, replace '.log' with '.log.gz'.
+              To ZIP rolled files, replace '.log' with '.log.zip'.
+            -->
+            <fileNamePattern>./logs/nifi-registry-app_%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!-- keep 30 log files worth of history -->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
+            <immediateFlush>true</immediateFlush>
+        </encoder>
+    </appender>
+
+    <appender name="BOOTSTRAP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${org.apache.nifi.registry.bootstrap.config.log.dir}/nifi-registry-bootstrap.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!--
+              For daily rollover, use 'user_%d.log'.
+              For hourly rollover, use 'user_%d{yyyy-MM-dd_HH}.log'.
+              To GZIP rolled files, replace '.log' with '.log.gz'.
+              To ZIP rolled files, replace '.log' with '.log.zip'.
+            -->
+            <fileNamePattern>${org.apache.nifi.registry.bootstrap.config.log.dir}/nifi-registry-bootstrap_%d.log</fileNamePattern>
+            <!-- keep 5 log files worth of history -->
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="EVENTS_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${org.apache.nifi.registry.bootstrap.config.log.dir}/nifi-registry-event.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!--
+              For daily rollover, use 'user_%d.log'.
+              For hourly rollover, use 'user_%d{yyyy-MM-dd_HH}.log'.
+              To GZIP rolled files, replace '.log' with '.log.gz'.
+              To ZIP rolled files, replace '.log' with '.log.zip'.
+            -->
+            <fileNamePattern>${org.apache.nifi.registry.bootstrap.config.log.dir}/nifi-registry-event_%d.log</fileNamePattern>
+            <!-- keep 5 log files worth of history -->
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%date ## %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%date %level [%thread] %logger{40} %msg%n</pattern>
+        </encoder>
+    </appender>
+    
+    <!-- valid logging levels: TRACE, DEBUG, INFO, WARN, ERROR -->
+    
+    <logger name="org.apache.nifi.registry" level="INFO"/>
+
+    <!-- To see SQL statements set this to DEBUG -->
+    <logger name="org.hibernate.SQL" level="INFO" />
+    <!-- To see the values in SQL statements set this to TRACE -->
+    <logger name="org.hibernate.type" level="INFO" />
+
+    <!--
+        Logger for capturing Bootstrap logs and NiFi Registry's standard error and standard out.
+    -->
+    <logger name="org.apache.nifi.registry.bootstrap" level="INFO" additivity="false">
+        <appender-ref ref="BOOTSTRAP_FILE" />
+    </logger>
+    <logger name="org.apache.nifi.registry.bootstrap.Command" level="INFO" additivity="false">
+        <appender-ref ref="CONSOLE" />
+        <appender-ref ref="BOOTSTRAP_FILE" />
+    </logger>
+
+    <!-- Everything written to NiFi Registry's Standard Out will be logged with the logger org.apache.nifi.StdOut at INFO level -->
+    <logger name="org.apache.nifi.registry.StdOut" level="INFO" additivity="false">
+        <appender-ref ref="BOOTSTRAP_FILE" />
+    </logger>
+
+    <!-- Everything written to NiFi Registry's Standard Error will be logged with the logger org.apache.nifi.StdErr at ERROR level -->
+    <logger name="org.apache.nifi.registry.StdErr" level="ERROR" additivity="false">
+        <appender-ref ref="BOOTSTRAP_FILE" />
+    </logger>
+
+    <!-- This will log all events to a separate file when the LoggingEventHookProvider is enabled in providers.xml -->
+    <logger name="org.apache.nifi.registry.provider.hook.LoggingEventHookProvider" level="INFO" additivity="false">
+        <appender-ref ref="EVENTS_FILE" />
+    </logger>
+
+    <root level="INFO">
+        <appender-ref ref="APP_FILE"/>
+    </root>
+    
+</configuration>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
new file mode 100644
index 0000000..fb77a07
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
@@ -0,0 +1,80 @@
+# 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.
+
+# web properties #
+nifi.registry.web.war.directory=${nifi.registry.web.war.directory}
+nifi.registry.web.http.host=${nifi.registry.web.http.host}
+nifi.registry.web.http.port=${nifi.registry.web.http.port}
+nifi.registry.web.https.host=${nifi.registry.web.https.host}
+nifi.registry.web.https.port=${nifi.registry.web.https.port}
+nifi.registry.web.jetty.working.directory=${nifi.registry.jetty.work.dir}
+nifi.registry.web.jetty.threads=${nifi.registry.web.jetty.threads}
+
+# security properties #
+nifi.registry.security.keystore=${nifi.registry.security.keystore}
+nifi.registry.security.keystoreType=${nifi.registry.security.keystoreType}
+nifi.registry.security.keystorePasswd=${nifi.registry.security.keystorePasswd}
+nifi.registry.security.keyPasswd=${nifi.registry.security.keyPasswd}
+nifi.registry.security.truststore=${nifi.registry.security.truststore}
+nifi.registry.security.truststoreType=${nifi.registry.security.truststoreType}
+nifi.registry.security.truststorePasswd=${nifi.registry.security.truststorePasswd}
+nifi.registry.security.needClientAuth=${nifi.registry.security.needClientAuth}
+nifi.registry.security.authorizers.configuration.file=${nifi.registry.security.authorizers.configuration.file}
+nifi.registry.security.authorizer=${nifi.registry.security.authorizer}
+nifi.registry.security.identity.providers.configuration.file=${nifi.registry.security.identity.providers.configuration.file}
+nifi.registry.security.identity.provider=${nifi.registry.security.identity.provider}
+
+# sensitive property protection properties #
+# nifi.registry.sensitive.props.additional.keys=
+
+# providers properties #
+nifi.registry.providers.configuration.file=${nifi.registry.providers.configuration.file}
+
+# legacy database properties, used to migrate data from original DB to new DB below
+# NOTE: Users upgrading from 0.1.0 should leave these populated, but new installs after 0.1.0 should leave these empty
+nifi.registry.db.directory=${nifi.registry.db.directory}
+nifi.registry.db.url.append=${nifi.registry.db.url.append}
+
+# database properties
+nifi.registry.db.url=${nifi.registry.db.url}
+nifi.registry.db.driver.class=${nifi.registry.db.driver.class}
+nifi.registry.db.driver.directory=${nifi.registry.db.driver.directory}
+nifi.registry.db.username=${nifi.registry.db.username}
+nifi.registry.db.password=${nifi.registry.db.password}
+nifi.registry.db.maxConnections=${nifi.registry.db.maxConnections}
+nifi.registry.db.sql.debug=${nifi.registry.db.sql.debug}
+
+# extension directories #
+# Each property beginning with "nifi.registry.extension.dir." will be treated as location for an extension,
+# and a class loader will be created for each location, with the system class loader as the parent
+#
+#nifi.registry.extension.dir.1=/path/to/extension1
+#nifi.registry.extension.dir.2=/path/to/extension2
+
+# Identity Mapping Properties #
+# These properties allow normalizing user identities such that identities coming from different identity providers
+# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
+# DNs from certificates and principals from Kerberos into a common identity string:
+#
+# nifi.registry.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
+# nifi.registry.security.identity.mapping.value.dn=$1@$2
+# nifi.registry.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
+# nifi.registry.security.identity.mapping.value.kerb=$1@$2
+
+# kerberos properties #
+nifi.registry.kerberos.krb5.file=${nifi.registry.kerberos.krb5.file}
+nifi.registry.kerberos.spnego.principal=${nifi.registry.kerberos.spnego.principal}
+nifi.registry.kerberos.spnego.keytab.location=${nifi.registry.kerberos.spnego.keytab.location}
+nifi.registry.kerberos.spnego.authentication.expiration=${nifi.registry.kerberos.spnego.authentication.expiration}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/providers.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/providers.xml b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/providers.xml
new file mode 100644
index 0000000..faf8d4f
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/providers.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+<providers>
+
+    <flowPersistenceProvider>
+        <class>org.apache.nifi.registry.provider.flow.FileSystemFlowPersistenceProvider</class>
+        <property name="Flow Storage Directory">./flow_storage</property>
+    </flowPersistenceProvider>
+
+    <!--
+    <flowPersistenceProvider>
+        <class>org.apache.nifi.registry.provider.flow.git.GitFlowPersistenceProvider</class>
+        <property name="Flow Storage Directory">./flow_storage</property>
+        <property name="Remote To Push"></property>
+        <property name="Remote Access User"></property>
+        <property name="Remote Access Password"></property>
+    </flowPersistenceProvider>
+    -->
+
+    <!--
+    <eventHookProvider>
+    	<class>org.apache.nifi.registry.provider.hook.ScriptEventHookProvider</class>
+    	<property name="Script Path"></property>
+    	<property name="Working Directory"></property>
+    	-->
+    	<!-- Optional Whitelist Event types
+        <property name="Whitelisted Event Type 1">CREATE_FLOW</property>
+        <property name="Whitelisted Event Type 2">DELETE_FLOW</property>
+    	-->
+    <!--
+    </eventHookProvider>
+    -->
+
+    <!-- This will log all events to a separate file specified by the EVENT_APPENDER in logback.xml -->
+    <!--
+    <eventHookProvider>
+        <class>org.apache.nifi.registry.provider.hook.LoggingEventHookProvider</class>
+    </eventHookProvider>
+    -->
+
+</providers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-runtime/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-runtime/pom.xml b/nifi-registry-core/nifi-registry-runtime/pom.xml
new file mode 100644
index 0000000..ed0fae4
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-runtime/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.nifi.registry</groupId>
+        <artifactId>nifi-registry-core</artifactId>
+        <version>0.3.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>nifi-registry-runtime</artifactId>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+            <artifactId>nifi-registry-utils</artifactId>
+            <version>0.3.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+            <artifactId>nifi-registry-properties</artifactId>
+            <version>0.3.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+            <artifactId>nifi-registry-jetty</artifactId>
+            <version>0.3.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jul-to-slf4j</artifactId>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/BootstrapListener.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/BootstrapListener.java b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/BootstrapListener.java
new file mode 100644
index 0000000..0eabe94
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/BootstrapListener.java
@@ -0,0 +1,395 @@
+/*
+ * 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.registry;
+
+import org.apache.nifi.registry.util.LimitingInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.management.LockInfo;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class BootstrapListener {
+
+    private static final Logger logger = LoggerFactory.getLogger(BootstrapListener.class);
+
+    private final NiFiRegistry nifi;
+    private final int bootstrapPort;
+    private final String secretKey;
+
+    private volatile Listener listener;
+    private volatile ServerSocket serverSocket;
+
+    public BootstrapListener(final NiFiRegistry nifi, final int bootstrapPort) {
+        this.nifi = nifi;
+        this.bootstrapPort = bootstrapPort;
+        secretKey = UUID.randomUUID().toString();
+    }
+
+    public void start() throws IOException {
+        logger.debug("Starting Bootstrap Listener to communicate with Bootstrap Port {}", bootstrapPort);
+
+        serverSocket = new ServerSocket();
+        serverSocket.bind(new InetSocketAddress("localhost", 0));
+        serverSocket.setSoTimeout(2000);
+
+        final int localPort = serverSocket.getLocalPort();
+        logger.info("Started Bootstrap Listener, Listening for incoming requests on port {}", localPort);
+
+        listener = new Listener(serverSocket);
+        final Thread listenThread = new Thread(listener);
+        listenThread.setDaemon(true);
+        listenThread.setName("Listen to Bootstrap");
+        listenThread.start();
+
+        logger.debug("Notifying Bootstrap that local port is {}", localPort);
+        sendCommand("PORT", new String[] { String.valueOf(localPort), secretKey});
+    }
+
+    public void stop() {
+        if (listener != null) {
+            listener.stop();
+        }
+    }
+
+    public void sendStartedStatus(boolean status) throws IOException {
+        logger.debug("Notifying Bootstrap that the status of starting NiFi Registry is {}", status);
+        sendCommand("STARTED", new String[]{ String.valueOf(status) });
+    }
+
+    private void sendCommand(final String command, final String[] args) throws IOException {
+        try (final Socket socket = new Socket()) {
+            socket.setSoTimeout(60000);
+            socket.connect(new InetSocketAddress("localhost", bootstrapPort));
+            socket.setSoTimeout(60000);
+
+            final StringBuilder commandBuilder = new StringBuilder(command);
+            for (final String arg : args) {
+                commandBuilder.append(" ").append(arg);
+            }
+            commandBuilder.append("\n");
+
+            final String commandWithArgs = commandBuilder.toString();
+            logger.debug("Sending command to Bootstrap: " + commandWithArgs);
+
+            final OutputStream out = socket.getOutputStream();
+            out.write((commandWithArgs).getBytes(StandardCharsets.UTF_8));
+            out.flush();
+
+            logger.debug("Awaiting response from Bootstrap...");
+            final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+            final String response = reader.readLine();
+            if ("OK".equals(response)) {
+                logger.info("Successfully initiated communication with Bootstrap");
+            } else {
+                logger.error("Failed to communicate with Bootstrap. Bootstrap may be unable to issue or receive commands from NiFi Registry ");
+            }
+        }
+    }
+
+    private class Listener implements Runnable {
+
+        private final ServerSocket serverSocket;
+        private final ExecutorService executor;
+        private volatile boolean stopped = false;
+
+        public Listener(final ServerSocket serverSocket) {
+            this.serverSocket = serverSocket;
+            this.executor = Executors.newFixedThreadPool(2);
+        }
+
+        public void stop() {
+            stopped = true;
+
+            executor.shutdownNow();
+
+            try {
+                serverSocket.close();
+            } catch (final IOException ioe) {
+                // nothing to really do here. we could log this, but it would just become
+                // confusing in the logs, as we're shutting down and there's no real benefit
+            }
+        }
+
+        @Override
+        public void run() {
+            while (!stopped) {
+                try {
+                    final Socket socket;
+                    try {
+                        logger.debug("Listening for Bootstrap Requests");
+                        socket = serverSocket.accept();
+                    } catch (final SocketTimeoutException ste) {
+                        if (stopped) {
+                            return;
+                        }
+
+                        continue;
+                    } catch (final IOException ioe) {
+                        if (stopped) {
+                            return;
+                        }
+
+                        throw ioe;
+                    }
+
+                    logger.debug("Received connection from Bootstrap");
+                    socket.setSoTimeout(5000);
+
+                    executor.submit(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                final BootstrapRequest request = readRequest(socket.getInputStream());
+                                final BootstrapRequest.RequestType requestType = request.getRequestType();
+
+                                switch (requestType) {
+                                    case PING:
+                                        logger.debug("Received PING request from Bootstrap; responding");
+                                        echoPing(socket.getOutputStream());
+                                        logger.debug("Responded to PING request from Bootstrap");
+                                        break;
+                                    case SHUTDOWN:
+                                        logger.info("Received SHUTDOWN request from Bootstrap");
+                                        echoShutdown(socket.getOutputStream());
+                                        nifi.shutdownHook();
+                                        return;
+                                    case DUMP:
+                                        logger.info("Received DUMP request from Bootstrap");
+                                        writeDump(socket.getOutputStream());
+                                        break;
+                                }
+                            } catch (final Throwable t) {
+                                logger.error("Failed to process request from Bootstrap due to " + t.toString(), t);
+                            } finally {
+                                try {
+                                    socket.close();
+                                } catch (final IOException ioe) {
+                                    logger.warn("Failed to close socket to Bootstrap due to {}", ioe.toString());
+                                }
+                            }
+                        }
+                    });
+                } catch (final Throwable t) {
+                    logger.error("Failed to process request from Bootstrap due to " + t.toString(), t);
+                }
+            }
+        }
+    }
+
+    private static void writeDump(final OutputStream out) throws IOException {
+        final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
+        final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
+
+        final ThreadInfo[] infos = mbean.dumpAllThreads(true, true);
+        final long[] deadlockedThreadIds = mbean.findDeadlockedThreads();
+        final long[] monitorDeadlockThreadIds = mbean.findMonitorDeadlockedThreads();
+
+        final List<ThreadInfo> sortedInfos = new ArrayList<>(infos.length);
+        for (final ThreadInfo info : infos) {
+            sortedInfos.add(info);
+        }
+        Collections.sort(sortedInfos, new Comparator<ThreadInfo>() {
+            @Override
+            public int compare(ThreadInfo o1, ThreadInfo o2) {
+                return o1.getThreadName().toLowerCase().compareTo(o2.getThreadName().toLowerCase());
+            }
+        });
+
+        final StringBuilder sb = new StringBuilder();
+        for (final ThreadInfo info : sortedInfos) {
+            sb.append("\n");
+            sb.append("\"").append(info.getThreadName()).append("\" Id=");
+            sb.append(info.getThreadId()).append(" ");
+            sb.append(info.getThreadState().toString()).append(" ");
+
+            switch (info.getThreadState()) {
+                case BLOCKED:
+                case TIMED_WAITING:
+                case WAITING:
+                    sb.append(" on ");
+                    sb.append(info.getLockInfo());
+                    break;
+                default:
+                    break;
+            }
+
+            if (info.isSuspended()) {
+                sb.append(" (suspended)");
+            }
+            if (info.isInNative()) {
+                sb.append(" (in native code)");
+            }
+
+            if (deadlockedThreadIds != null && deadlockedThreadIds.length > 0) {
+                for (final long id : deadlockedThreadIds) {
+                    if (id == info.getThreadId()) {
+                        sb.append(" ** DEADLOCKED THREAD **");
+                    }
+                }
+            }
+
+            if (monitorDeadlockThreadIds != null && monitorDeadlockThreadIds.length > 0) {
+                for (final long id : monitorDeadlockThreadIds) {
+                    if (id == info.getThreadId()) {
+                        sb.append(" ** MONITOR-DEADLOCKED THREAD **");
+                    }
+                }
+            }
+
+            final StackTraceElement[] stackTraces = info.getStackTrace();
+            for (final StackTraceElement element : stackTraces) {
+                sb.append("\n\tat ").append(element);
+
+                final MonitorInfo[] monitors = info.getLockedMonitors();
+                for (final MonitorInfo monitor : monitors) {
+                    if (monitor.getLockedStackFrame().equals(element)) {
+                        sb.append("\n\t- waiting on ").append(monitor);
+                    }
+                }
+            }
+
+            final LockInfo[] lockInfos = info.getLockedSynchronizers();
+            if (lockInfos.length > 0) {
+                sb.append("\n\t");
+                sb.append("Number of Locked Synchronizers: ").append(lockInfos.length);
+                for (final LockInfo lockInfo : lockInfos) {
+                    sb.append("\n\t- ").append(lockInfo.toString());
+                }
+            }
+
+            sb.append("\n");
+        }
+
+        if (deadlockedThreadIds != null && deadlockedThreadIds.length > 0) {
+            sb.append("\n\nDEADLOCK DETECTED!");
+            sb.append("\nThe following thread IDs are deadlocked:");
+            for (final long id : deadlockedThreadIds) {
+                sb.append("\n").append(id);
+            }
+        }
+
+        if (monitorDeadlockThreadIds != null && monitorDeadlockThreadIds.length > 0) {
+            sb.append("\n\nMONITOR DEADLOCK DETECTED!");
+            sb.append("\nThe following thread IDs are deadlocked:");
+            for (final long id : monitorDeadlockThreadIds) {
+                sb.append("\n").append(id);
+            }
+        }
+
+        writer.write(sb.toString());
+        writer.flush();
+    }
+
+    private void echoPing(final OutputStream out) throws IOException {
+        out.write("PING\n".getBytes(StandardCharsets.UTF_8));
+        out.flush();
+    }
+
+    private void echoShutdown(final OutputStream out) throws IOException {
+        out.write("SHUTDOWN\n".getBytes(StandardCharsets.UTF_8));
+        out.flush();
+    }
+
+    @SuppressWarnings("resource")  // we don't want to close the stream, as the caller will do that
+    private BootstrapRequest readRequest(final InputStream in) throws IOException {
+        // We want to ensure that we don't try to read data from an InputStream directly
+        // by a BufferedReader because any user on the system could open a socket and send
+        // a multi-gigabyte file without any new lines in order to crash the NiFi instance
+        // (or at least cause OutOfMemoryErrors, which can wreak havoc on the running instance).
+        // So we will limit the Input Stream to only 4 KB, which should be plenty for any request.
+        final LimitingInputStream limitingIn = new LimitingInputStream(in, 4096);
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(limitingIn));
+
+        final String line = reader.readLine();
+        final String[] splits = line.split(" ");
+        if (splits.length < 1) {
+            throw new IOException("Received invalid request from Bootstrap: " + line);
+        }
+
+        final String requestType = splits[0];
+        final String[] args;
+        if (splits.length == 1) {
+            throw new IOException("Received invalid request from Bootstrap; request did not have a secret key; request type = " + requestType);
+        } else if (splits.length == 2) {
+            args = new String[0];
+        } else {
+            args = Arrays.copyOfRange(splits, 2, splits.length);
+        }
+
+        final String requestKey = splits[1];
+        if (!secretKey.equals(requestKey)) {
+            throw new IOException("Received invalid Secret Key for request type " + requestType);
+        }
+
+        try {
+            return new BootstrapRequest(requestType, args);
+        } catch (final Exception e) {
+            throw new IOException("Received invalid request from Bootstrap; request type = " + requestType);
+        }
+    }
+
+    private static class BootstrapRequest {
+
+        public static enum RequestType {
+
+            SHUTDOWN,
+            DUMP,
+            PING;
+        }
+
+        private final RequestType requestType;
+        private final String[] args;
+
+        public BootstrapRequest(final String request, final String[] args) {
+            this.requestType = RequestType.valueOf(request);
+            this.args = args;
+        }
+
+        public RequestType getRequestType() {
+            return requestType;
+        }
+
+        @SuppressWarnings("unused")
+        public String[] getArgs() {
+            return args;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
new file mode 100644
index 0000000..65fdcf4
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
@@ -0,0 +1,197 @@
+/*
+ * 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.registry;
+
+import org.apache.nifi.registry.jetty.JettyServer;
+import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoader;
+import org.apache.nifi.registry.properties.SensitivePropertyProtectionException;
+import org.apache.nifi.registry.security.crypto.BootstrapFileCryptoKeyProvider;
+import org.apache.nifi.registry.security.crypto.CryptoKeyProvider;
+import org.apache.nifi.registry.security.crypto.MissingCryptoKeyException;
+import org.apache.nifi.registry.util.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Main entry point for NiFiRegistry.
+ */
+public class NiFiRegistry {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NiFiRegistry.class);
+
+    public static final String BOOTSTRAP_PORT_PROPERTY = "nifi.registry.bootstrap.listen.port";
+
+    public static final String NIFI_REGISTRY_PROPERTIES_FILE_PATH_PROPERTY = "nifi.registry.properties.file.path";
+    public static final String NIFI_REGISTRY_BOOTSTRAP_FILE_PATH_PROPERTY = "nifi.registry.bootstrap.config.file.path";
+
+    public static final String RELATIVE_BOOTSTRAP_FILE_LOCATION = "conf/bootstrap.conf";
+    public static final String RELATIVE_PROPERTIES_FILE_LOCATION = "conf/nifi-registry.properties";
+
+    private final JettyServer server;
+    private final BootstrapListener bootstrapListener;
+    private volatile boolean shutdown = false;
+
+    public NiFiRegistry(final NiFiRegistryProperties properties, CryptoKeyProvider masterKeyProvider)
+            throws ClassNotFoundException, IOException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+
+        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(final Thread t, final Throwable e) {
+                LOGGER.error("An Unknown Error Occurred in Thread {}: {}", t, e.toString());
+                LOGGER.error("", e);
+            }
+        });
+
+        // register the shutdown hook
+        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // shutdown the jetty server
+                shutdownHook();
+            }
+        }));
+
+        final String bootstrapPort = System.getProperty(BOOTSTRAP_PORT_PROPERTY);
+        if (bootstrapPort != null) {
+            try {
+                final int port = Integer.parseInt(bootstrapPort);
+
+                if (port < 1 || port > 65535) {
+                    throw new RuntimeException("Failed to start NiFi Registry because system property '" + BOOTSTRAP_PORT_PROPERTY + "' is not a valid integer in the range 1 - 65535");
+                }
+
+                bootstrapListener = new BootstrapListener(this, port);
+                bootstrapListener.start();
+            } catch (final NumberFormatException nfe) {
+                throw new RuntimeException("Failed to start NiFi Registry because system property '" + BOOTSTRAP_PORT_PROPERTY + "' is not a valid integer in the range 1 - 65535");
+            }
+        } else {
+            LOGGER.info("NiFi Registry started without Bootstrap Port information provided; will not listen for requests from Bootstrap");
+            bootstrapListener = null;
+        }
+
+        // delete the web working dir - if the application does not start successfully
+        // the web app directories might be in an invalid state. when this happens
+        // jetty will not attempt to re-extract the war into the directory. by removing
+        // the working directory, we can be assured that it will attempt to extract the
+        // war every time the application starts.
+        File webWorkingDir = properties.getWebWorkingDirectory();
+        FileUtils.deleteFilesInDirectory(webWorkingDir, null, LOGGER, true, true);
+        FileUtils.deleteFile(webWorkingDir, LOGGER, 3);
+
+        // redirect JUL log events
+        SLF4JBridgeHandler.removeHandlersForRootLogger();
+        SLF4JBridgeHandler.install();
+
+        final long startTime = System.nanoTime();
+        server = new JettyServer(properties, masterKeyProvider);
+
+        if (shutdown) {
+            LOGGER.info("NiFi Registry has been shutdown via NiFi Registry Bootstrap. Will not start Controller");
+        } else {
+            server.start();
+
+            if (bootstrapListener != null) {
+                bootstrapListener.sendStartedStatus(true);
+            }
+
+            final long duration = System.nanoTime() - startTime;
+            LOGGER.info("Registry initialization took " + duration + " nanoseconds "
+                    + "(" + (int) TimeUnit.SECONDS.convert(duration, TimeUnit.NANOSECONDS) + " seconds).");
+        }
+    }
+
+    protected void shutdownHook() {
+        try {
+            this.shutdown = true;
+
+            LOGGER.info("Initiating shutdown of Jetty web server...");
+            if (server != null) {
+                server.stop();
+            }
+            if (bootstrapListener != null) {
+                bootstrapListener.stop();
+            }
+            LOGGER.info("Jetty web server shutdown completed (nicely or otherwise).");
+        } catch (final Throwable t) {
+            LOGGER.warn("Problem occurred ensuring Jetty web server was properly terminated due to " + t);
+        }
+    }
+
+    /**
+     * Main entry point of the application.
+     *
+     * @param args things which are ignored
+     */
+    public static void main(String[] args) {
+        LOGGER.info("Launching NiFi Registry...");
+
+        final CryptoKeyProvider masterKeyProvider;
+        final NiFiRegistryProperties properties;
+        try {
+            final String bootstrapConfigFilePath = System.getProperty(NIFI_REGISTRY_BOOTSTRAP_FILE_PATH_PROPERTY, RELATIVE_BOOTSTRAP_FILE_LOCATION);
+            masterKeyProvider = new BootstrapFileCryptoKeyProvider(bootstrapConfigFilePath);
+            LOGGER.info("Read property protection key from {}", bootstrapConfigFilePath);
+            properties = initializeProperties(masterKeyProvider);
+        } catch (final IllegalArgumentException iae) {
+            throw new RuntimeException("Unable to load properties: " + iae, iae);
+        }
+
+        try {
+            new NiFiRegistry(properties, masterKeyProvider);
+        } catch (final Throwable t) {
+            LOGGER.error("Failure to launch NiFi Registry due to " + t, t);
+        }
+    }
+
+    private static NiFiRegistryProperties initializeProperties(CryptoKeyProvider masterKeyProvider) {
+
+        String key = CryptoKeyProvider.EMPTY_KEY;
+        try {
+            key = masterKeyProvider.getKey();
+        } catch (MissingCryptoKeyException e) {
+            LOGGER.debug("CryptoKeyProvider provided to initializeProperties method was empty - did not contain a key.");
+            // Do nothing. The key can be empty when it is passed to the loader as the loader will only use it if any properties are protected.
+        }
+
+        try {
+            try {
+                // Load properties using key. If properties are protected and key missing, throw RuntimeException
+                final String nifiRegistryPropertiesFilePath = System.getProperty(NIFI_REGISTRY_PROPERTIES_FILE_PATH_PROPERTY, RELATIVE_PROPERTIES_FILE_LOCATION);
+                final NiFiRegistryProperties properties = NiFiRegistryPropertiesLoader.withKey(key).load(nifiRegistryPropertiesFilePath);
+                LOGGER.info("Loaded {} properties", properties.size());
+                return properties;
+            } catch (SensitivePropertyProtectionException e) {
+                final String msg = "There was an issue decrypting protected properties";
+                LOGGER.error(msg, e);
+                throw new IllegalArgumentException(msg);
+            }
+        } catch (IllegalArgumentException e) {
+            final String msg = "The bootstrap process did not provide a valid key and there are protected properties present in the properties file";
+            LOGGER.error(msg, e);
+            throw new IllegalArgumentException(msg);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/util/LimitingInputStream.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/util/LimitingInputStream.java b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/util/LimitingInputStream.java
new file mode 100644
index 0000000..c069ec2
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/util/LimitingInputStream.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class LimitingInputStream extends InputStream {
+
+    private final InputStream in;
+    private final long limit;
+    private long bytesRead = 0;
+
+    public LimitingInputStream(final InputStream in, final long limit) {
+        this.in = in;
+        this.limit = limit;
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (bytesRead >= limit) {
+            return -1;
+        }
+
+        final int val = in.read();
+        if (val > -1) {
+            bytesRead++;
+        }
+        return val;
+    }
+
+    @Override
+    public int read(final byte[] b) throws IOException {
+        if (bytesRead >= limit) {
+            return -1;
+        }
+
+        final int maxToRead = (int) Math.min(b.length, limit - bytesRead);
+
+        final int val = in.read(b, 0, maxToRead);
+        if (val > 0) {
+            bytesRead += val;
+        }
+        return val;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (bytesRead >= limit) {
+            return -1;
+        }
+
+        final int maxToRead = (int) Math.min(len, limit - bytesRead);
+
+        final int val = in.read(b, off, maxToRead);
+        if (val > 0) {
+            bytesRead += val;
+        }
+        return val;
+    }
+
+    @Override
+    public long skip(final long n) throws IOException {
+        final long skipped = in.skip(Math.min(n, limit - bytesRead));
+        bytesRead += skipped;
+        return skipped;
+    }
+
+    @Override
+    public int available() throws IOException {
+        return in.available();
+    }
+
+    @Override
+    public void close() throws IOException {
+        in.close();
+    }
+
+    @Override
+    public void mark(int readlimit) {
+        in.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+
+    @Override
+    public void reset() throws IOException {
+        in.reset();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-security-api/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-security-api/pom.xml b/nifi-registry-core/nifi-registry-security-api/pom.xml
new file mode 100644
index 0000000..5100569
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-security-api/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nifi-registry-core</artifactId>
+        <groupId>org.apache.nifi.registry</groupId>
+        <version>0.3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>nifi-registry-security-api</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi.registry</groupId>
+            <artifactId>nifi-registry-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationRequest.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationRequest.java b/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationRequest.java
new file mode 100644
index 0000000..72ae50e
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationRequest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.registry.security.authentication;
+
+import java.io.Serializable;
+
+public class AuthenticationRequest implements Serializable {
+
+    private String username;
+    private Object credentials;
+    private Object details;
+
+    public AuthenticationRequest(String username, Object credentials, Object details) {
+        this.username = username;
+        this.credentials = credentials;
+        this.details = details;
+    }
+
+    public AuthenticationRequest() {}
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Object getCredentials() {
+        return credentials;
+    }
+
+    public void setCredentials(Object credentials) {
+        this.credentials = credentials;
+    }
+
+    public Object getDetails() {
+        return details;
+    }
+
+    public void setDetails(Object details) {
+        this.details = details;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AuthenticationRequest that = (AuthenticationRequest) o;
+
+        return username != null ? username.equals(that.username) : that.username == null;
+    }
+
+    @Override
+    public int hashCode() {
+        return username != null ? username.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "AuthenticationRequest{" +
+                "username='" + username + '\'' +
+                ", credentials=[PROTECTED]" +
+                ", details=" + details +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/6f26290d/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationResponse.java
----------------------------------------------------------------------
diff --git a/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationResponse.java b/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationResponse.java
new file mode 100644
index 0000000..b8eb721
--- /dev/null
+++ b/nifi-registry-core/nifi-registry-security-api/src/main/java/org/apache/nifi/registry/security/authentication/AuthenticationResponse.java
@@ -0,0 +1,98 @@
+/*
+ * 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.registry.security.authentication;
+
+import java.io.Serializable;
+
+/**
+ * Authentication response for a user login attempt.
+ */
+public class AuthenticationResponse implements Serializable {
+
+    private final String identity;
+    private final String username;
+    private final long expiration;
+    private final String issuer;
+
+    /**
+     * Creates an authentication response. The username and how long the authentication is valid in milliseconds
+     *
+     * @param identity The user identity
+     * @param username The username
+     * @param expiration The expiration in milliseconds
+     * @param issuer The issuer of the token
+     */
+    public AuthenticationResponse(final String identity, final String username, final long expiration, final String issuer) {
+        this.identity = identity;
+        this.username = username;
+        this.expiration = expiration;
+        this.issuer = issuer;
+    }
+
+    public String getIdentity() {
+        return identity;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getIssuer() {
+        return issuer;
+    }
+
+    /**
+     * Returns the expiration of a given authentication in milliseconds.
+     *
+     * @return The expiration in milliseconds
+     */
+    public long getExpiration() {
+        return expiration;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AuthenticationResponse that = (AuthenticationResponse) o;
+
+        if (expiration != that.expiration) return false;
+        if (identity != null ? !identity.equals(that.identity) : that.identity != null) return false;
+        if (username != null ? !username.equals(that.username) : that.username != null) return false;
+        return issuer != null ? issuer.equals(that.issuer) : that.issuer == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = identity != null ? identity.hashCode() : 0;
+        result = 31 * result + (username != null ? username.hashCode() : 0);
+        result = 31 * result + (int) (expiration ^ (expiration >>> 32));
+        result = 31 * result + (issuer != null ? issuer.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "AuthenticationResponse{" +
+                "identity='" + identity + '\'' +
+                ", username='" + username + '\'' +
+                ", expiration=" + expiration +
+                ", issuer='" + issuer + '\'' +
+                '}';
+    }
+}