nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mcgil...@apache.org
Subject [28/51] [abbrv] nifi git commit: NIFI-655: - Refactoring web security to use Spring Security Java Configuration. - Introducing security in Web UI in order to get JWT.
Date Tue, 01 Dec 2015 16:44:06 GMT
http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestUser.java
index 52f4522..621dc09 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestUser.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestUser.java
@@ -22,8 +22,7 @@ import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.core.util.MultivaluedMapImpl;
 import java.util.Map;
 import javax.ws.rs.core.MediaType;
-import org.apache.nifi.web.security.DnUtils;
-import org.apache.nifi.web.security.x509.X509AuthenticationFilter;
+import org.apache.nifi.web.security.ProxiedEntitiesUtils;
 
 /**
  *
@@ -35,9 +34,27 @@ public class NiFiTestUser {
     private final Client client;
     private final String proxyDn;
 
-    public NiFiTestUser(Client client, String dn) {
+    public NiFiTestUser(Client client, String proxyDn) {
         this.client = client;
-        this.proxyDn = DnUtils.formatProxyDn(dn);
+        if (proxyDn != null) {
+            this.proxyDn = ProxiedEntitiesUtils.formatProxyDn(proxyDn);
+        } else {
+            this.proxyDn = null;
+        }
+    }
+
+    /**
+     * Conditionally adds the proxied entities chain.
+     *
+     * @param builder the resource builder
+     * @return the resource builder
+     */
+    private WebResource.Builder addProxiedEntities(final WebResource.Builder builder) {
+        if (proxyDn == null) {
+            return builder;
+        } else {
+            return builder.header(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN, proxyDn);
+        }
     }
 
     /**
@@ -59,6 +76,18 @@ public class NiFiTestUser {
      * @return response
      */
     public ClientResponse testGet(String url, Map<String, String> queryParams) {
+        return testGetWithHeaders(url, queryParams, null);
+    }
+
+    /**
+     * Performs a GET using the specified url and query parameters.
+     *
+     * @param url url
+     * @param queryParams params
+     * @param headers http headers
+     * @return response
+     */
+    public ClientResponse testGetWithHeaders(String url, Map<String, String> queryParams, Map<String, String> headers) {
         // get the resource
         WebResource resource = client.resource(url);
 
@@ -69,8 +98,18 @@ public class NiFiTestUser {
             }
         }
 
+        // get the builder
+        WebResource.Builder builder = addProxiedEntities(resource.accept(MediaType.APPLICATION_JSON));
+
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                builder = builder.header(key, headers.get(key));
+            }
+        }
+
         // perform the query
-        return resource.accept(MediaType.APPLICATION_JSON).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn).get(ClientResponse.class);
+        return builder.get(ClientResponse.class);
     }
 
     /**
@@ -93,14 +132,34 @@ public class NiFiTestUser {
      * @throws Exception ex
      */
     public ClientResponse testPost(String url, Object entity) throws Exception {
+        return testPostWithHeaders(url, entity, null);
+    }
+
+    /**
+     * Performs a POST using the specified url and entity body.
+     *
+     * @param url url
+     * @param entity entity
+     * @param headers http headers
+     * @return response
+     * @throws Exception ex
+     */
+    public ClientResponse testPostWithHeaders(String url, Object entity, Map<String, String> headers) throws Exception {
         // get the resource
-        WebResource.Builder resourceBuilder = client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON));
 
         // include the request entity
         if (entity != null) {
             resourceBuilder = resourceBuilder.entity(entity);
         }
 
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
         // perform the request
         return resourceBuilder.post(ClientResponse.class);
     }
@@ -110,18 +169,38 @@ public class NiFiTestUser {
      *
      * @param url url
      * @param entity entity
-     * @return repsonse
+     * @return response
      * @throws Exception ex
      */
     public ClientResponse testPostMultiPart(String url, Object entity) throws Exception {
+        return testPostMultiPartWithHeaders(url, entity, null);
+    }
+
+    /**
+     * Performs a POST using the specified url and entity body.
+     *
+     * @param url url
+     * @param entity entity
+     * @param headers http headers
+     * @return response
+     * @throws Exception ex
+     */
+    public ClientResponse testPostMultiPartWithHeaders(String url, Object entity, Map<String, String> headers) throws Exception {
         // get the resource
-        WebResource.Builder resourceBuilder = client.resource(url).accept(MediaType.APPLICATION_XML).type(MediaType.MULTIPART_FORM_DATA).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_XML).type(MediaType.MULTIPART_FORM_DATA));
 
         // include the request entity
         if (entity != null) {
             resourceBuilder = resourceBuilder.entity(entity);
         }
 
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
         // perform the request
         return resourceBuilder.post(ClientResponse.class);
     }
@@ -135,6 +214,19 @@ public class NiFiTestUser {
      * @throws java.lang.Exception ex
      */
     public ClientResponse testPost(String url, Map<String, String> formData) throws Exception {
+        return testPostWithHeaders(url, formData, null);
+    }
+
+    /**
+     * Performs a POST using the specified url and form data.
+     *
+     * @param url url
+     * @param formData form data
+     * @param headers http headers
+     * @return response
+     * @throws java.lang.Exception ex
+     */
+    public ClientResponse testPostWithHeaders(String url, Map<String, String> formData, Map<String, String> headers) throws Exception {
         // convert the form data
         MultivaluedMapImpl entity = new MultivaluedMapImpl();
         for (String key : formData.keySet()) {
@@ -142,14 +234,20 @@ public class NiFiTestUser {
         }
 
         // get the resource
-        WebResource.Builder resourceBuilder
-                = client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED));
 
         // add the form data if necessary
         if (!entity.isEmpty()) {
             resourceBuilder = resourceBuilder.entity(entity);
         }
 
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
         // perform the request
         return resourceBuilder.post(ClientResponse.class);
     }
@@ -163,14 +261,34 @@ public class NiFiTestUser {
      * @throws java.lang.Exception ex
      */
     public ClientResponse testPut(String url, Object entity) throws Exception {
+        return testPutWithHeaders(url, entity, null);
+    }
+
+    /**
+     * Performs a PUT using the specified url and entity body.
+     *
+     * @param url url
+     * @param entity entity
+     * @param headers http headers
+     * @return response
+     * @throws java.lang.Exception ex
+     */
+    public ClientResponse testPutWithHeaders(String url, Object entity, Map<String, String> headers) throws Exception {
         // get the resource
-        WebResource.Builder resourceBuilder = client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON));
 
         // include the request entity
         if (entity != null) {
             resourceBuilder = resourceBuilder.entity(entity);
         }
 
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
         // perform the request
         return resourceBuilder.put(ClientResponse.class);
     }
@@ -184,6 +302,19 @@ public class NiFiTestUser {
      * @throws java.lang.Exception ex
      */
     public ClientResponse testPut(String url, Map<String, String> formData) throws Exception {
+        return testPutWithHeaders(url, formData, null);
+    }
+
+    /**
+     * Performs a PUT using the specified url and form data.
+     *
+     * @param url url
+     * @param formData form data
+     * @param headers http headers
+     * @return response
+     * @throws java.lang.Exception ex
+     */
+    public ClientResponse testPutWithHeaders(String url, Map<String, String> formData, Map<String, String> headers) throws Exception {
         // convert the form data
         MultivaluedMapImpl entity = new MultivaluedMapImpl();
         for (String key : formData.keySet()) {
@@ -191,14 +322,20 @@ public class NiFiTestUser {
         }
 
         // get the resource
-        WebResource.Builder resourceBuilder
-                = client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED));
 
         // add the form data if necessary
         if (!entity.isEmpty()) {
             resourceBuilder = resourceBuilder.entity(entity);
         }
 
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
         // perform the request
         return resourceBuilder.put(ClientResponse.class);
     }
@@ -211,24 +348,26 @@ public class NiFiTestUser {
      * @throws java.lang.Exception ex
      */
     public ClientResponse testDelete(String url) throws Exception {
-        return testDelete(url, (Object) null);
+        return testDelete(url, null);
     }
 
     /**
      * Performs a DELETE using the specified url and entity.
      *
      * @param url url
-     * @param entity entity
-     * @return repsonse
+     * @param headers http headers
+     * @return response
      * @throws java.lang.Exception ex
      */
-    public ClientResponse testDelete(String url, Object entity) throws Exception {
+    public ClientResponse testDeleteWithHeaders(String url, Map<String, String> headers) throws Exception {
         // get the resource
-        WebResource.Builder resourceBuilder = client.resource(url).accept(MediaType.APPLICATION_JSON).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn);
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.APPLICATION_JSON));
 
-        // append any query parameters
-        if (entity != null) {
-            resourceBuilder = resourceBuilder.entity(entity);
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
         }
 
         // perform the query
@@ -255,7 +394,56 @@ public class NiFiTestUser {
         }
 
         // perform the request
-        return resource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED).header(X509AuthenticationFilter.PROXY_ENTITIES_CHAIN, proxyDn).delete(ClientResponse.class);
+        return addProxiedEntities(resource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED)).delete(ClientResponse.class);
     }
 
+    /**
+     * Attempts to create a token with the specified username and password.
+     *
+     * @param url the url
+     * @param username the username
+     * @param password the password
+     * @return response
+     * @throws Exception ex
+     */
+    public ClientResponse testCreateToken(String url, String username, String password) throws Exception {
+        // convert the form data
+        MultivaluedMapImpl entity = new MultivaluedMapImpl();
+        entity.add("username", username);
+        entity.add("password", password);
+
+        // get the resource
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.TEXT_PLAIN).type(MediaType.APPLICATION_FORM_URLENCODED)).entity(entity);
+
+        // perform the request
+        return resourceBuilder.post(ClientResponse.class);
+    }
+
+    /**
+     * Attempts to create a token with the specified username and password.
+     *
+     * @param url the url
+     * @param justification justification
+     * @param headers http headers
+     * @return response
+     * @throws Exception ex
+     */
+    public ClientResponse testRegisterUser(String url, String justification, Map<String, String> headers) throws Exception {
+        // convert the form data
+        MultivaluedMapImpl entity = new MultivaluedMapImpl();
+        entity.add("justification", justification);
+
+        // get the resource
+        WebResource.Builder resourceBuilder = addProxiedEntities(client.resource(url).accept(MediaType.TEXT_PLAIN).type(MediaType.APPLICATION_FORM_URLENCODED)).entity(entity);
+
+        // append any headers
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                resourceBuilder = resourceBuilder.header(key, headers.get(key));
+            }
+        }
+
+        // perform the request
+        return resourceBuilder.post(ClientResponse.class);
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider
new file mode 100644
index 0000000..4b42e4f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider
@@ -0,0 +1,15 @@
+# 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.
+org.apache.nifi.integration.util.NiFiTestLoginIdentityProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/controller-services.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/controller-services.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/controller-services.xml
deleted file mode 100644
index f5bd96a..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/controller-services.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?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.
--->
-<services>
-
-</services>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/login-identity-providers.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/login-identity-providers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/login-identity-providers.xml
new file mode 100644
index 0000000..04120c9
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/login-identity-providers.xml
@@ -0,0 +1,24 @@
+<?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 all authority providers to use when running securely.
+-->
+<loginIdentityProviders>
+    <provider>
+        <identifier>test-provider</identifier>
+        <class>org.apache.nifi.integration.util.NiFiTestLoginIdentityProvider</class>
+    </provider>
+</loginIdentityProviders>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties
index 0aa5a14..10db651 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties
@@ -14,16 +14,15 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.version=nifi 0.2.1-SNAPSHOT 
+nifi.version=nifi version 
 nifi.flow.configuration.file=
 nifi.flow.configuration.archive.dir=target/archive
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
 nifi.flowservice.writedelay.interval=2 sec
 
-nifi.reporting.task.configuration.file=target/test-classes/access-control/reporting-tasks.xml
-nifi.controller.service.configuration.file=target/test-classes/access-control/controller-services.xml
 nifi.authority.provider.configuration.file=target/test-classes/access-control/authority-providers.xml
+nifi.login.identity.provider.configuration.file=target/test-classes/access-control/login-identity-providers.xml
 nifi.templates.directory=target/test-classes/access-control/templates
 nifi.ui.banner.text=TEST BANNER
 nifi.ui.autorefresh.interval=30 sec
@@ -93,10 +92,11 @@ nifi.security.truststoreType=JKS
 nifi.security.truststorePasswd=localtest
 nifi.security.needClientAuth=true
 nifi.security.user.authority.provider=test-provider
+nifi.security.user.login.identity.provider=test-provider
 nifi.security.authorizedUsers.file=target/test-classes/access-control/users.xml
 nifi.security.user.credential.cache.duration=1 hr
 nifi.security.support.new.account.requests=
-nifi.security.default.user.roles=
+nifi.security.anonymous.authorities=
 
 # cluster common properties (cluster manager and nodes must have same values) #
 nifi.cluster.protocol.heartbeat.interval=5 sec

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/reporting-tasks.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/reporting-tasks.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/reporting-tasks.xml
deleted file mode 100644
index 251735e..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/reporting-tasks.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.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.
--->
-<tasks>
-</tasks>

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
index daeef5c..ee18bff 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
@@ -22,6 +22,40 @@
     </parent>
     <groupId>org.apache.nifi</groupId>
     <artifactId>nifi-web-security</artifactId>
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <directory>src/main/xsd</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>jaxb2-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>current</id>
+                        <goals>
+                            <goal>xjc</goal>
+                        </goals>
+                        <configuration>
+                            <packageName>org.apache.nifi.authentication.generated</packageName>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <configuration>
+                    <excludes>**/authentication/generated/*.java,</excludes>
+                </configuration>
+            </plugin>            
+        </plugins>
+    </build>
     <dependencies>
         <dependency>
             <groupId>org.apache.nifi</groupId>
@@ -29,6 +63,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-nar-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-api</artifactId>
         </dependency>
         <dependency>
@@ -40,6 +78,11 @@
             <artifactId>nifi-framework-core</artifactId>
         </dependency>
         <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.6.0</version>
+        </dependency>
+        <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk16</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/DnUtils.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/DnUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/DnUtils.java
deleted file mode 100644
index f3bd11e..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/DnUtils.java
+++ /dev/null
@@ -1,85 +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.
- */
-package org.apache.nifi.web.security;
-
-import java.security.cert.X509Certificate;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.servlet.http.HttpServletRequest;
-import org.apache.nifi.web.security.x509.SubjectDnX509PrincipalExtractor;
-import org.apache.nifi.web.security.x509.X509CertificateExtractor;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- *
- */
-public class DnUtils {
-
-    private static final Pattern proxyChainPattern = Pattern.compile("<(.*?)>");
-
-    /**
-     * @param request http request
-     * @return the X-ProxiedEntitiesChain from the specified request
-     */
-    public static String getXProxiedEntitiesChain(final HttpServletRequest request) {
-        String xProxiedEntitiesChain = request.getHeader("X-ProxiedEntitiesChain");
-        final X509Certificate cert = new X509CertificateExtractor().extractClientCertificate(request);
-        if (cert != null) {
-            final SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
-            final String extractedPrincipal = principalExtractor.extractPrincipal(cert).toString();
-            final String formattedPrincipal = formatProxyDn(extractedPrincipal);
-            if (StringUtils.isBlank(xProxiedEntitiesChain)) {
-                xProxiedEntitiesChain = formattedPrincipal;
-            } else {
-                xProxiedEntitiesChain += formattedPrincipal;
-            }
-        }
-
-        return xProxiedEntitiesChain;
-    }
-
-    /**
-     * Formats the specified DN to be set as a HTTP header using well known
-     * conventions.
-     *
-     * @param dn raw dn
-     * @return the dn formatted as an HTTP header
-     */
-    public static String formatProxyDn(String dn) {
-        return "<" + dn + ">";
-    }
-
-    /**
-     * Tokenizes the specified proxy chain.
-     *
-     * @param rawProxyChain raw chain
-     * @return tokenized proxy chain
-     */
-    public static Deque<String> tokenizeProxyChain(String rawProxyChain) {
-        final Deque<String> dnList = new ArrayDeque<>();
-
-        // parse the proxy chain
-        final Matcher rawProxyChainMatcher = proxyChainPattern.matcher(rawProxyChain);
-        while (rawProxyChainMatcher.find()) {
-            dnList.push(rawProxyChainMatcher.group(1));
-        }
-
-        return dnList;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/InvalidAuthenticationException.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/InvalidAuthenticationException.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/InvalidAuthenticationException.java
new file mode 100644
index 0000000..1065152
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/InvalidAuthenticationException.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * Thrown if the authentication of a given request is invalid. For instance,
+ * an expired certificate or token.
+ */
+public class InvalidAuthenticationException extends AuthenticationException {
+
+    public InvalidAuthenticationException(String msg) {
+        super(msg);
+    }
+
+    public InvalidAuthenticationException(String msg, Throwable t) {
+        super(msg, t);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationEntryPoint.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/NiFiAuthenticationEntryPoint.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationEntryPoint.java
new file mode 100644
index 0000000..ef1dfb2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationEntryPoint.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+/**
+ * This is our own implementation of org.springframework.security.web.AuthenticationEntryPoint that allows us to send the response to the client exactly how we want to and log the results.
+ */
+public class NiFiAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+    private static final Logger logger = LoggerFactory.getLogger(NiFiAuthenticationEntryPoint.class);
+
+    private final NiFiProperties properties;
+
+    public NiFiAuthenticationEntryPoint(NiFiProperties properties) {
+        this.properties = properties;
+    }
+
+    /**
+     * Always returns a 403 error code to the client.
+     *
+     * @param request request
+     * @param response response
+     * @param ae ae
+     * @throws java.io.IOException ex
+     * @throws javax.servlet.ServletException ex
+     */
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ae) throws IOException, ServletException {
+        // if the content type is not set, mark as access denied
+        if (StringUtils.isBlank(response.getContentType())) {
+            // write the response message
+            PrintWriter out = response.getWriter();
+            response.setContentType("text/plain");
+
+            // return authorized if the request is secure and this nifi supports new account requests
+            if (request.isSecure() && properties.getSupportNewAccountRequests()) {
+                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                out.println("Not authorized.");
+            } else {
+                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+                out.println("Access is denied.");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.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/NiFiAuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
new file mode 100644
index 0000000..f09d610
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
@@ -0,0 +1,209 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
+import org.apache.nifi.web.security.user.NiFiUserUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AccountStatusException;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+/**
+ *
+ */
+public abstract class NiFiAuthenticationFilter implements Filter {
+
+    private static final Logger logger = LoggerFactory.getLogger(NiFiAuthenticationFilter.class);
+
+    private AuthenticationManager authenticationManager;
+    private NiFiProperties properties;
+
+    @Override
+    public void init(final FilterConfig filterConfig) throws ServletException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Checking secure context token: " + SecurityContextHolder.getContext().getAuthentication());
+        }
+
+        if (requiresAuthentication((HttpServletRequest) request)) {
+            authenticate((HttpServletRequest) request, (HttpServletResponse) response);
+        }
+
+        chain.doFilter(request, response);
+    }
+
+    private boolean requiresAuthentication(final HttpServletRequest request) {
+        // continue attempting authorization if the user is anonymous
+        if (isAnonymousUser()) {
+            return true;
+        }
+
+        // or there is no user yet
+        return NiFiUserUtils.getNiFiUser() == null && NiFiUserUtils.getNewAccountRequest() == null;
+    }
+
+    private boolean isAnonymousUser() {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+        return user != null && NiFiUser.ANONYMOUS_USER_IDENTITY.equals(user.getIdentity());
+    }
+
+    private void authenticate(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+        try {
+            final NiFiAuthenticationRequestToken authenticated = attemptAuthentication(request, response);
+            if (authenticated != null) {
+                // log the request attempt - response details will be logged later
+                logger.info(String.format("Attempting request for (%s) %s %s (source ip: %s)",
+                        ProxiedEntitiesUtils.formatProxyDn(StringUtils.join(authenticated.getChain(), "><")), request.getMethod(),
+                        request.getRequestURL().toString(), request.getRemoteAddr()));
+
+                final Authentication authorized = authenticationManager.authenticate(authenticated);
+                successfulAuthorization(request, response, authorized);
+            }
+        } catch (final AuthenticationException ae) {
+            if (!isAnonymousUser()) {
+                unsuccessfulAuthorization(request, response, ae);
+            }
+        }
+    }
+
+    public abstract NiFiAuthenticationRequestToken attemptAuthentication(HttpServletRequest request, HttpServletResponse response);
+
+    protected void successfulAuthorization(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Authentication success: " + authResult);
+        }
+
+        SecurityContextHolder.getContext().setAuthentication(authResult);
+        ProxiedEntitiesUtils.successfulAuthorization(request, response, authResult);
+    }
+
+    protected void unsuccessfulAuthorization(HttpServletRequest request, HttpServletResponse response, AuthenticationException ae) throws IOException {
+        // populate the response
+        ProxiedEntitiesUtils.unsuccessfulAuthorization(request, response, ae);
+
+        // set the response status
+        response.setContentType("text/plain");
+
+        // write the response message
+        PrintWriter out = response.getWriter();
+
+        // use the type of authentication exception to determine the response code
+        if (ae instanceof UsernameNotFoundException) {
+            if (properties.getSupportNewAccountRequests()) {
+                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+                out.println("Not authorized.");
+            } else {
+                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+                out.println("Access is denied.");
+            }
+        } else if (ae instanceof InvalidAuthenticationException) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            out.println(ae.getMessage());
+        } else if (ae instanceof AccountStatusException) {
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            out.println(ae.getMessage());
+        } else if (ae instanceof UntrustedProxyException) {
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            out.println(ae.getMessage());
+        } else if (ae instanceof AuthenticationServiceException) {
+            logger.error(String.format("Unable to authorize: %s", ae.getMessage()), ae);
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            out.println(String.format("Unable to authorize: %s", ae.getMessage()));
+        } else {
+            logger.error(String.format("Unable to authorize: %s", ae.getMessage()), ae);
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            out.println("Access is denied.");
+        }
+
+        // log the failure
+        logger.info(String.format("Rejecting access to web api: %s", ae.getMessage()));
+
+        // optionally log the stack trace
+        if (logger.isDebugEnabled()) {
+            logger.debug(StringUtils.EMPTY, ae);
+        }
+    }
+
+    /**
+     * Determines if the specified request is attempting to register a new user account.
+     *
+     * @param request http request
+     * @return true if new user
+     */
+    protected final boolean isNewAccountRequest(HttpServletRequest request) {
+        if ("POST".equalsIgnoreCase(request.getMethod())) {
+            String path = request.getPathInfo();
+            if (StringUtils.isNotBlank(path)) {
+                if ("/controller/users".equals(path)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Extracts the justification from the specified request.
+     *
+     * @param request The request
+     * @return The justification
+     */
+    protected final String getJustification(HttpServletRequest request) {
+        // get the justification
+        String justification = request.getParameter("justification");
+        if (justification == null) {
+            justification = StringUtils.EMPTY;
+        }
+        return justification;
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.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/NiFiAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
new file mode 100644
index 0000000..eb0684b
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import org.apache.nifi.web.security.token.NewAccountAuthenticationRequestToken;
+import org.apache.nifi.web.security.token.NewAccountAuthenticationToken;
+import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
+import org.apache.nifi.web.security.token.NiFiAuthorizationToken;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+/**
+ *
+ */
+public class NiFiAuthenticationProvider implements AuthenticationProvider {
+
+    private final AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService;
+
+    public NiFiAuthenticationProvider(final AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> userDetailsService) {
+        this.userDetailsService = userDetailsService;
+    }
+
+    @Override
+    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+        final NiFiAuthenticationRequestToken request = (NiFiAuthenticationRequestToken) authentication;
+
+        try {
+            // defer to the nifi user details service to authorize the user
+            final UserDetails userDetails = userDetailsService.loadUserDetails(request);
+
+            // build an authentication for accesing nifi
+            final NiFiAuthorizationToken result = new NiFiAuthorizationToken(userDetails);
+            result.setDetails(request.getDetails());
+            return result;
+        } catch (final UsernameNotFoundException unfe) {
+            // if the authentication request is for a new account and it could not be authorized because the user was not found,
+            // return the token so the new account could be created. this must go here toe nsure that any proxies have been authorized
+            if (isNewAccountAuthenticationToken(request)) {
+                return new NewAccountAuthenticationToken(((NewAccountAuthenticationRequestToken) authentication).getNewAccountRequest());
+            } else {
+                throw unfe;
+            }
+        }
+    }
+
+    private boolean isNewAccountAuthenticationToken(final Authentication authentication) {
+        return NewAccountAuthenticationRequestToken.class.isAssignableFrom(authentication.getClass());
+    }
+
+    @Override
+    public boolean supports(Class<?> authentication) {
+        return NiFiAuthenticationRequestToken.class.isAssignableFrom(authentication);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.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/ProxiedEntitiesUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
new file mode 100644
index 0000000..1b2f28a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.user.NiFiUser;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ *
+ */
+public class ProxiedEntitiesUtils {
+
+    public static final String PROXY_ENTITIES_CHAIN = "X-ProxiedEntitiesChain";
+    public static final String PROXY_ENTITIES_ACCEPTED = "X-ProxiedEntitiesAccepted";
+    public static final String PROXY_ENTITIES_DETAILS = "X-ProxiedEntitiesDetails";
+
+    private static final Pattern proxyChainPattern = Pattern.compile("<(.*?)>");
+
+    /**
+     * Formats the specified DN to be set as a HTTP header using well known conventions.
+     *
+     * @param dn raw dn
+     * @return the dn formatted as an HTTP header
+     */
+    public static String formatProxyDn(String dn) {
+        return "<" + dn + ">";
+    }
+
+    /**
+     * Tokenizes the specified proxy chain.
+     *
+     * @param rawProxyChain raw chain
+     * @return tokenized proxy chain
+     */
+    public static List<String> tokenizeProxiedEntitiesChain(String rawProxyChain) {
+        final List<String> proxyChain = new ArrayList<>();
+        final Matcher rawProxyChainMatcher = proxyChainPattern.matcher(rawProxyChain);
+        while (rawProxyChainMatcher.find()) {
+            proxyChain.add(rawProxyChainMatcher.group(1));
+        }
+
+        return proxyChain;
+    }
+
+    /**
+     * Builds the proxy chain for the specified user.
+     *
+     * @param user The current user
+     * @return The proxy chain for that user in String form
+     */
+    public static String buildProxiedEntitiesChainString(final NiFiUser user) {
+        // calculate the dn chain
+        final List<String> proxyChain = buildProxiedEntitiesChain(user);
+        return formatProxyDn(StringUtils.join(proxyChain, "><"));
+    }
+
+    /**
+     * Builds the proxy chain for the specified user.
+     *
+     * @param user The current user
+     * @return The proxy chain for that user in List form
+     */
+    public static List<String> buildProxiedEntitiesChain(final NiFiUser user) {
+        // calculate the dn chain
+        final List<String> proxyChain = new ArrayList<>();
+
+        // build the dn chain
+        NiFiUser chainedUser = user;
+        do {
+            // add the entry for this user
+            proxyChain.add(chainedUser.getIdentity());
+
+            // go to the next user in the chain
+            chainedUser = chainedUser.getChain();
+        } while (chainedUser != null);
+
+        return proxyChain;
+    }
+
+    /**
+     * Builds the proxy chain from the specified request and user.
+     *
+     * @param request the request
+     * @param username the username
+     * @return the proxy chain in list form
+     */
+    public static List<String> buildProxiedEntitiesChain(final HttpServletRequest request, final String username) {
+        final String chain = buildProxiedEntitiesChainString(request, username);
+        return tokenizeProxiedEntitiesChain(chain);
+    }
+
+    /**
+     * Builds the dn chain from the specified request and user.
+     *
+     * @param request the request
+     * @param username the username
+     * @return the dn chain in string form
+     */
+    public static String buildProxiedEntitiesChainString(final HttpServletRequest request, final String username) {
+        String principal;
+        if (username.startsWith("<") && username.endsWith(">")) {
+            principal = username;
+        } else {
+            principal = formatProxyDn(username);
+        }
+
+        // look for a proxied user
+        if (StringUtils.isNotBlank(request.getHeader(PROXY_ENTITIES_CHAIN))) {
+            principal = request.getHeader(PROXY_ENTITIES_CHAIN) + principal;
+        }
+        return principal;
+    }
+
+    public static void successfulAuthorization(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
+        if (StringUtils.isNotBlank(request.getHeader(PROXY_ENTITIES_CHAIN))) {
+            response.setHeader(PROXY_ENTITIES_ACCEPTED, Boolean.TRUE.toString());
+        }
+    }
+
+    public static void unsuccessfulAuthorization(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
+        if (StringUtils.isNotBlank(request.getHeader(PROXY_ENTITIES_CHAIN))) {
+            response.setHeader(PROXY_ENTITIES_DETAILS, failed.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.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/anonymous/NiFiAnonymousUserFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
index 295f09c..e67ed2c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
@@ -16,25 +16,22 @@
  */
 package org.apache.nifi.web.security.anonymous;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.EnumSet;
 import javax.servlet.http.HttpServletRequest;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.admin.service.AdministrationException;
 import org.apache.nifi.admin.service.UserService;
+import org.apache.nifi.authorization.Authority;
 import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.security.token.NiFiAuthorizationToken;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
 
 /**
- * Custom AnonymouseAuthenticationFilter used to grant additional authorities
- * depending on the current operating mode.
+ * Custom AnonymouseAuthenticationFilter used to grant additional authorities depending on the current operating mode.
  */
 public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
@@ -42,7 +39,6 @@ public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
     private static final String ANONYMOUS_KEY = "anonymousNifiKey";
 
-    private NiFiProperties properties;
     private UserService userService;
 
     public NiFiAnonymousUserFilter() {
@@ -51,51 +47,37 @@ public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
     @Override
     protected Authentication createAuthentication(HttpServletRequest request) {
-        Authentication authentication;
+        Authentication authentication = null;
+
         try {
             // load the anonymous user from the database
-            NiFiUser user = userService.getUserByDn(NiFiUser.ANONYMOUS_USER_DN);
-            NiFiUserDetails userDetails = new NiFiUserDetails(user);
+            NiFiUser user = userService.getUserByDn(NiFiUser.ANONYMOUS_USER_IDENTITY);
+
+            // if this is an unsecure request allow full access
+            if (!request.isSecure()) {
+                user.getAuthorities().addAll(EnumSet.allOf(Authority.class));
+            }
+
+            // only create an authentication token if the anonymous user has some authorities
+            if (!user.getAuthorities().isEmpty()) {
+                NiFiUserDetails userDetails = new NiFiUserDetails(user);
 
-            // get the granted authorities
-            List<GrantedAuthority> authorities = new ArrayList<>(userDetails.getAuthorities());
-            authentication = new AnonymousAuthenticationToken(ANONYMOUS_KEY, userDetails, authorities);
+                // get the granted authorities
+                authentication = new NiFiAuthorizationToken(userDetails);
+            }
         } catch (AdministrationException ase) {
             // record the issue
             anonymousUserFilterLogger.warn("Unable to load anonymous user from accounts database: " + ase.getMessage());
             if (anonymousUserFilterLogger.isDebugEnabled()) {
                 anonymousUserFilterLogger.warn(StringUtils.EMPTY, ase);
             }
-
-            // defer to the base implementation
-            authentication = super.createAuthentication(request);
         }
         return authentication;
     }
 
-    /**
-     * Only supports anonymous users for non-secure requests or one way ssl.
-     *
-     * @param request request
-     * @return true if allowed
-     */
-    @Override
-    protected boolean applyAnonymousForThisRequest(HttpServletRequest request) {
-        // anonymous for non secure requests
-        if ("http".equalsIgnoreCase(request.getScheme())) {
-            return true;
-        }
-
-        return !properties.getNeedClientAuth();
-    }
-
     /* setters */
     public void setUserService(UserService userService) {
         this.userService = userService;
     }
 
-    public void setProperties(NiFiProperties properties) {
-        this.properties = properties;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authentication/NiFiAuthenticationEntryPoint.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/authentication/NiFiAuthenticationEntryPoint.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authentication/NiFiAuthenticationEntryPoint.java
deleted file mode 100644
index cd5f1ac..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authentication/NiFiAuthenticationEntryPoint.java
+++ /dev/null
@@ -1,69 +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.
- */
-package org.apache.nifi.web.security.authentication;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.WebAttributes;
-
-/**
- * This is our own implementation of
- * org.springframework.security.web.AuthenticationEntryPoint that allows us to
- * send the response to the client exactly how we want to and log the results.
- */
-public class NiFiAuthenticationEntryPoint implements AuthenticationEntryPoint {
-
-    private static final Logger logger = LoggerFactory.getLogger(NiFiAuthenticationEntryPoint.class);
-
-    /**
-     * Always returns a 403 error code to the client.
-     *
-     * @param request request
-     * @param response response
-     * @param ae ae
-     * @throws java.io.IOException ex
-     * @throws javax.servlet.ServletException ex
-     */
-    @Override
-    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException ae) throws IOException, ServletException {
-        // get the last exception - the exception that is being passed in is a generic no credentials found
-        // exception because the authentication could not be found in the security context. the actual cause
-        // of the problem is stored in the session as the authentication_exception
-        Object authenticationException = request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
-
-        // log request result
-        if (authenticationException instanceof AuthenticationException) {
-            ae = (AuthenticationException) authenticationException;
-            logger.info(String.format("Rejecting access to web api: %s", ae.getMessage()));
-        }
-
-        // set the response status
-        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
-        response.setContentType("text/plain");
-
-        // write the response message
-        PrintWriter out = response.getWriter();
-        out.println("Access is denied.");
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NiFiAuthorizationService.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/authorization/NiFiAuthorizationService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NiFiAuthorizationService.java
index 95b4669..23d9e61 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NiFiAuthorizationService.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NiFiAuthorizationService.java
@@ -16,34 +16,35 @@
  */
 package org.apache.nifi.web.security.authorization;
 
-import java.util.Deque;
-import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.admin.service.AccountDisabledException;
 import org.apache.nifi.admin.service.AccountNotFoundException;
 import org.apache.nifi.admin.service.AccountPendingException;
 import org.apache.nifi.admin.service.AdministrationException;
 import org.apache.nifi.admin.service.UserService;
 import org.apache.nifi.authorization.Authority;
-import org.apache.nifi.web.security.DnUtils;
 import org.apache.nifi.user.NiFiUser;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.security.UntrustedProxyException;
 import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DataAccessException;
 import org.springframework.security.authentication.AccountStatusException;
 import org.springframework.security.authentication.AuthenticationServiceException;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
 import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
 /**
  * UserDetailsService that will verify user identity and grant user authorities.
  */
-public class NiFiAuthorizationService implements UserDetailsService {
+public class NiFiAuthorizationService implements AuthenticationUserDetailsService<NiFiAuthenticationRequestToken> {
 
     private static final Logger logger = LoggerFactory.getLogger(NiFiAuthorizationService.class);
 
@@ -53,35 +54,33 @@ public class NiFiAuthorizationService implements UserDetailsService {
     /**
      * Loads the user details for the specified dn.
      *
-     * Synchronizing because we want each request to be authorized atomically
-     * since each may contain any number of DNs. We wanted an access decision
-     * made for each individual request as a whole (without other request
-     * potentially impacting it).
+     * Synchronizing because we want each request to be authorized atomically since each may contain any number of DNs. We wanted an access decision made for each individual request as a whole
+     * (without other request potentially impacting it).
      *
-     * @param rawProxyChain proxy chain
+     * @param request request
      * @return user details
      * @throws UsernameNotFoundException ex
      * @throws org.springframework.dao.DataAccessException ex
      */
     @Override
-    public synchronized UserDetails loadUserByUsername(String rawProxyChain) throws UsernameNotFoundException, DataAccessException {
+    public synchronized UserDetails loadUserDetails(NiFiAuthenticationRequestToken request) throws UsernameNotFoundException, DataAccessException {
         NiFiUserDetails userDetails = null;
-        final Deque<String> dnList = DnUtils.tokenizeProxyChain(rawProxyChain);
+        final List<String> chain = new ArrayList<>(request.getChain());
 
         // ensure valid input
-        if (dnList.size() == 0) {
-            logger.warn("Malformed proxy chain: " + rawProxyChain);
+        if (chain.isEmpty()) {
+            logger.warn("Malformed proxy chain: " + StringUtils.join(request.getChain()));
             throw new UntrustedProxyException("Malformed proxy chain.");
         }
 
         NiFiUser proxy = null;
 
         // process each part of the proxy chain
-        for (final Iterator<String> dnIter = dnList.iterator(); dnIter.hasNext();) {
-            final String dn = dnIter.next();
+        for (final ListIterator<String> chainIter = request.getChain().listIterator(chain.size()); chainIter.hasPrevious();) {
+            final String dn = chainIter.previous();
 
             // if there is another dn after this one, this dn is a proxy for the request
-            if (dnIter.hasNext()) {
+            if (chainIter.hasPrevious()) {
                 try {
                     // get the user details for the proxy
                     final NiFiUserDetails proxyDetails = getNiFiUserDetails(dn);
@@ -108,9 +107,6 @@ public class NiFiAuthorizationService implements UserDetailsService {
 
                             // attempt to create a new user account for the proxying client
                             userService.createPendingUserAccount(dn, "Automatic account request generated for unknown proxy.");
-
-                            // propagate the exception to return the appropriate response
-                            throw new UsernameNotFoundException(String.format("An account request was generated for the proxy '%s'.", dn));
                         } catch (AdministrationException ae) {
                             throw new AuthenticationServiceException(String.format("Unable to create an account request for '%s': %s", dn, ae.getMessage()), ae);
                         } catch (IllegalArgumentException iae) {
@@ -121,10 +117,10 @@ public class NiFiAuthorizationService implements UserDetailsService {
                             throw new AccountStatusException(message) {
                             };
                         }
-                    } else {
-                        logger.warn(String.format("Untrusted proxy '%s' must be authorized with '%s' authority: %s", dn, Authority.ROLE_PROXY.toString(), unfe.getMessage()));
-                        throw new UntrustedProxyException(String.format("Untrusted proxy '%s' must be authorized with '%s'.", dn, Authority.ROLE_PROXY.toString()));
                     }
+
+                    logger.warn(String.format("Untrusted proxy '%s' must be authorized with '%s' authority: %s", dn, Authority.ROLE_PROXY.toString(), unfe.getMessage()));
+                    throw new UntrustedProxyException(String.format("Untrusted proxy '%s' must be authorized with '%s'.", dn, Authority.ROLE_PROXY.toString()));
                 } catch (AuthenticationException ae) {
                     logger.warn(String.format("Untrusted proxy '%s' must be authorized with '%s' authority: %s", dn, Authority.ROLE_PROXY.toString(), ae.getMessage()));
                     throw new UntrustedProxyException(String.format("Untrusted proxy '%s' must be authorized with '%s'.", dn, Authority.ROLE_PROXY.toString()));

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NodeAuthorizedUserFilter.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/authorization/NodeAuthorizedUserFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NodeAuthorizedUserFilter.java
deleted file mode 100644
index 80feed7..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/authorization/NodeAuthorizedUserFilter.java
+++ /dev/null
@@ -1,128 +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.
- */
-package org.apache.nifi.web.security.authorization;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.security.cert.X509Certificate;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import org.apache.nifi.controller.FlowController;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.web.security.x509.SubjectDnX509PrincipalExtractor;
-import org.apache.nifi.web.security.x509.X509CertificateExtractor;
-import org.apache.nifi.user.NiFiUser;
-import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.util.WebUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.security.authentication.AuthenticationDetailsSource;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
-import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
-import org.springframework.web.context.support.WebApplicationContextUtils;
-import org.springframework.web.filter.GenericFilterBean;
-
-/**
- * Custom filter to extract a user's authorities from the request where the user
- * was authenticated by the cluster manager and populate the threadlocal with
- * the authorized user. If the request contains the appropriate header with
- * authorities and the application instance is a node connected to the cluster,
- * then the authentication/authorization steps remaining in the filter chain are
- * skipped.
- *
- * Checking if the application instance is a connected node is important because
- * it prevents external clients from faking the request headers and bypassing
- * the authentication processing chain.
- */
-public class NodeAuthorizedUserFilter extends GenericFilterBean {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(NodeAuthorizedUserFilter.class);
-
-    public static final String PROXY_USER_DETAILS = "X-ProxiedEntityUserDetails";
-
-    private NiFiProperties properties;
-    private final AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
-    private final X509CertificateExtractor certificateExtractor = new X509CertificateExtractor();
-    private final X509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
-
-    @Override
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-        final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
-
-        // get the proxied user's authorities
-        final String hexEncodedUserDetails = httpServletRequest.getHeader(PROXY_USER_DETAILS);
-
-        // check if the request has the necessary header information and this instance is configured as a node
-        if (StringUtils.isNotBlank(hexEncodedUserDetails) && properties.isNode()) {
-
-            // get the flow controller from the Spring context
-            final ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
-            final FlowController flowController = ctx.getBean("flowController", FlowController.class);
-
-            // check that we are connected to the cluster
-            if (flowController.getNodeId() != null) {
-                try {
-                    // get the DN from the cert in the request
-                    final X509Certificate certificate = certificateExtractor.extractClientCertificate((HttpServletRequest) request);
-                    if (certificate != null) {
-                        // extract the principal from the certificate
-                        final Object certificatePrincipal = principalExtractor.extractPrincipal(certificate);
-                        final String dn = certificatePrincipal.toString();
-
-                        // only consider the pre-authorized user when the request came from the NCM according to the DN in the certificate
-                        final String clusterManagerDN = flowController.getClusterManagerDN();
-                        if (clusterManagerDN != null && clusterManagerDN.equals(dn)) {
-                            // deserialize hex encoded object
-                            final Serializable userDetailsObj = WebUtils.deserializeHexToObject(hexEncodedUserDetails);
-
-                            // if we have a valid object, set the authentication token and bypass the remaining authentication processing chain
-                            if (userDetailsObj instanceof NiFiUserDetails) {
-                                final NiFiUserDetails userDetails = (NiFiUserDetails) userDetailsObj;
-                                final NiFiUser user = userDetails.getNiFiUser();
-
-                                // log the request attempt - response details will be logged later
-                                logger.info(String.format("Attempting request for (%s) %s %s (source ip: %s)", user.getDn(), httpServletRequest.getMethod(),
-                                        httpServletRequest.getRequestURL().toString(), request.getRemoteAddr()));
-
-                                // we do not create the authentication token with the X509 certificate because the certificate is from the sending system, not the proxied user
-                                final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(userDetails, null, userDetails.getAuthorities());
-                                token.setDetails(authenticationDetailsSource.buildDetails(request));
-                                SecurityContextHolder.getContext().setAuthentication(token);
-                            }
-                        }
-                    }
-                } catch (final ClassNotFoundException cnfe) {
-                    LOGGER.warn("Classpath issue detected because failed to deserialize authorized user in request header due to: " + cnfe, cnfe);
-                }
-            }
-        }
-
-        chain.doFilter(request, response);
-    }
-
-    /* setters */
-    public void setProperties(NiFiProperties properties) {
-        this.properties = properties;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.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/jwt/JwtAuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..20675fb
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationFilter.java
@@ -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.
+ */
+package org.apache.nifi.web.security.jwt;
+
+import io.jsonwebtoken.JwtException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.web.security.NiFiAuthenticationFilter;
+import org.apache.nifi.web.security.token.NewAccountAuthenticationRequestToken;
+import org.apache.nifi.web.security.token.NiFiAuthenticationRequestToken;
+import org.apache.nifi.web.security.user.NewAccountRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import org.apache.nifi.web.security.InvalidAuthenticationException;
+
+/**
+ */
+public class JwtAuthenticationFilter extends NiFiAuthenticationFilter {
+
+    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
+
+    private static final String AUTHORIZATION = "Authorization";
+
+    private JwtService jwtService;
+
+    @Override
+    public NiFiAuthenticationRequestToken attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
+        // only suppport jwt login when running securely
+        if (!request.isSecure()) {
+            return null;
+        }
+
+        // TODO: Refactor request header extraction logic to shared utility as it is duplicated in AccessResource
+
+        // get the principal out of the user token
+        final String authorization = request.getHeader(AUTHORIZATION);
+
+        // if there is no authorization header, we don't know the user
+        if (authorization == null) {
+            return null;
+        } else {
+            // Extract the Base64 encoded token from the Authorization header
+            final String token = StringUtils.substringAfterLast(authorization, " ");
+
+            try {
+                final String jwtPrincipal = jwtService.getAuthenticationFromToken(token);
+
+                if (isNewAccountRequest(request)) {
+                    return new NewAccountAuthenticationRequestToken(new NewAccountRequest(Arrays.asList(jwtPrincipal), getJustification(request)));
+                } else {
+                    return new NiFiAuthenticationRequestToken(Arrays.asList(jwtPrincipal));
+                }
+            } catch (JwtException e) {
+                throw new InvalidAuthenticationException(e.getMessage(), e);
+            }
+        }
+    }
+
+    public void setJwtService(JwtService jwtService) {
+        this.jwtService = jwtService;
+    }
+
+}


Mime
View raw message