You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2016/06/30 11:58:01 UTC

[1/4] nifi git commit: NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592

Repository: nifi
Updated Branches:
  refs/heads/master 65d895827 -> ae9e2fdf0


http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/test/java/org/apache/nifi/provenance/TestPersistentProvenanceRepository.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/test/java/org/apache/nifi/provenance/TestPersistentProvenanceRepository.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/test/java/org/apache/nifi/provenance/TestPersistentProvenanceRepository.java
index 3238d97..5417669 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/test/java/org/apache/nifi/provenance/TestPersistentProvenanceRepository.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/test/java/org/apache/nifi/provenance/TestPersistentProvenanceRepository.java
@@ -19,6 +19,7 @@ package org.apache.nifi.provenance;
 import static org.apache.nifi.provenance.TestUtil.createFlowFile;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
@@ -39,6 +40,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 import java.util.zip.GZIPOutputStream;
 
 import org.apache.lucene.analysis.Analyzer;
@@ -51,6 +53,8 @@ import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.store.FSDirectory;
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.provenance.lineage.EventNode;
@@ -173,7 +177,7 @@ public class TestPersistentProvenanceRepository {
         config.setJournalCount(10);
         config.setQueryThreadPoolSize(10);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("abc", "xyz");
@@ -221,7 +225,7 @@ public class TestPersistentProvenanceRepository {
         System.out.println("Closing and re-initializing");
         repo.close();
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
         System.out.println("Re-initialized");
 
         final long fetchStart = System.nanoTime();
@@ -241,7 +245,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxEventFileCapacity(1L);
         config.setMaxEventFileLife(1, TimeUnit.SECONDS);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("abc", "xyz");
@@ -267,7 +271,7 @@ public class TestPersistentProvenanceRepository {
         Thread.sleep(500L); // Give the repo time to shutdown (i.e., close all file handles, etc.)
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
         final List<ProvenanceEventRecord> recoveredRecords = repo.getEvents(0L, 12);
 
         assertEquals(10, recoveredRecords.size());
@@ -290,7 +294,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxEventFileLife(2, TimeUnit.SECONDS);
         config.setSearchableFields(searchableFields);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("abc", "xyz");
@@ -331,7 +335,7 @@ public class TestPersistentProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.ComponentID, "XXXX"));
         query.setMaxResults(100);
 
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(2, result.getMatchingEvents().size());
         for (final ProvenanceEventRecord match : result.getMatchingEvents()) {
             System.out.println(match);
@@ -344,7 +348,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -375,7 +379,7 @@ public class TestPersistentProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
         query.setMaxResults(100);
 
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(10, result.getMatchingEvents().size());
         for (final ProvenanceEventRecord match : result.getMatchingEvents()) {
             System.out.println(match);
@@ -388,7 +392,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
         config.setCompressOnRollover(true);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -426,7 +430,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "10000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -458,7 +462,7 @@ public class TestPersistentProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
         query.setMaxResults(100);
 
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(10, result.getMatchingEvents().size());
         for (final ProvenanceEventRecord match : result.getMatchingEvents()) {
             System.out.println(match);
@@ -471,7 +475,7 @@ public class TestPersistentProvenanceRepository {
         repo.purgeOldEvents();
         Thread.sleep(2000L);
 
-        final QueryResult newRecordSet = repo.queryEvents(query);
+        final QueryResult newRecordSet = repo.queryEvents(query, createUser());
         assertTrue(newRecordSet.getMatchingEvents().isEmpty());
     }
 
@@ -486,7 +490,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -525,7 +529,7 @@ public class TestPersistentProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
         query.setMaxResults(100);
 
-        final QuerySubmission submission = repo.submitQuery(query);
+        final QuerySubmission submission = repo.submitQuery(query, createUser());
         while (!submission.getResult().isFinished()) {
             Thread.sleep(100L);
         }
@@ -555,7 +559,7 @@ public class TestPersistentProvenanceRepository {
         Thread.sleep(2000L); // purge is async. Give it time to do its job.
 
         query.setMaxResults(100);
-        final QuerySubmission noResultSubmission = repo.submitQuery(query);
+        final QuerySubmission noResultSubmission = repo.submitQuery(query, createUser());
         while (!noResultSubmission.getResult().isFinished()) {
             Thread.sleep(10L);
         }
@@ -573,7 +577,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -601,7 +605,7 @@ public class TestPersistentProvenanceRepository {
         final Query query = new Query(UUID.randomUUID().toString());
         query.setMaxResults(100);
 
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(10, result.getMatchingEvents().size());
         for (final ProvenanceEventRecord match : result.getMatchingEvents()) {
             System.out.println(match);
@@ -615,7 +619,7 @@ public class TestPersistentProvenanceRepository {
 
         Thread.sleep(1000L);
 
-        final QueryResult newRecordSet = repo.queryEvents(query);
+        final QueryResult newRecordSet = repo.queryEvents(query, createUser());
         assertTrue(newRecordSet.getMatchingEvents().isEmpty());
     }
 
@@ -629,7 +633,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000001";
         final Map<String, String> attributes = new HashMap<>();
@@ -655,7 +659,7 @@ public class TestPersistentProvenanceRepository {
 
         repo.waitForRollover();
 
-        final Lineage lineage = repo.computeLineage(uuid);
+        final Lineage lineage = repo.computeLineage(uuid, createUser());
         assertNotNull(lineage);
 
         // Nodes should consist of a RECEIVE followed by FlowFileNode, followed by a DROP
@@ -684,7 +688,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000001";
         final Map<String, String> attributes = new HashMap<>();
@@ -710,7 +714,7 @@ public class TestPersistentProvenanceRepository {
 
         repo.waitForRollover();
 
-        final AsyncLineageSubmission submission = repo.submitLineageComputation(uuid);
+        final AsyncLineageSubmission submission = repo.submitLineageComputation(uuid, createUser());
         while (!submission.getResult().isFinished()) {
             Thread.sleep(100L);
         }
@@ -743,7 +747,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String childId = "00000000-0000-0000-0000-000000000000";
 
@@ -773,7 +777,7 @@ public class TestPersistentProvenanceRepository {
 
         repo.waitForRollover();
 
-        final Lineage lineage = repo.computeLineage(childId);
+        final Lineage lineage = repo.computeLineage(childId, createUser());
         assertNotNull(lineage);
 
         // these are not necessarily accurate asserts....
@@ -793,7 +797,7 @@ public class TestPersistentProvenanceRepository {
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String childId = "00000000-0000-0000-0000-000000000000";
 
@@ -823,7 +827,7 @@ public class TestPersistentProvenanceRepository {
 
         repo.waitForRollover();
 
-        final AsyncLineageSubmission submission = repo.submitLineageComputation(childId);
+        final AsyncLineageSubmission submission = repo.submitLineageComputation(childId, createUser());
         while (!submission.getResult().isFinished()) {
             Thread.sleep(100L);
         }
@@ -840,7 +844,7 @@ public class TestPersistentProvenanceRepository {
         final RepositoryConfiguration config = createConfiguration();
         config.setMaxEventFileLife(1, TimeUnit.SECONDS);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -866,13 +870,13 @@ public class TestPersistentProvenanceRepository {
         repo.close();
 
         final PersistentProvenanceRepository secondRepo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        secondRepo.initialize(getEventReporter());
+        secondRepo.initialize(getEventReporter(), null, null);
 
         try {
             final ProvenanceEventRecord event11 = builder.build();
             secondRepo.registerEvent(event11);
             secondRepo.waitForRollover();
-            final ProvenanceEventRecord event11Retrieved = secondRepo.getEvent(10L);
+            final ProvenanceEventRecord event11Retrieved = secondRepo.getEvent(10L, null);
             assertNotNull(event11Retrieved);
             assertEquals(10, event11Retrieved.getEventId());
         } finally {
@@ -897,7 +901,7 @@ public class TestPersistentProvenanceRepository {
         in.writeInt(4);
         in.close();
         assertTrue(eventFile.exists());
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(10, result.getMatchingEvents().size());
     }
 
@@ -914,7 +918,7 @@ public class TestPersistentProvenanceRepository {
         query.setMaxResults(100);
         DataOutputStream in = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(eventFile)));
         in.close();
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(10, result.getMatchingEvents().size());
     }
 
@@ -927,7 +931,7 @@ public class TestPersistentProvenanceRepository {
         config.setDesiredIndexSize(10);
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         String uuid = UUID.randomUUID().toString();
         for (int i = 0; i < 20; i++) {
@@ -957,7 +961,7 @@ public class TestPersistentProvenanceRepository {
         config.setDesiredIndexSize(10); // force new index to be created for each rollover
 
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -1003,7 +1007,7 @@ public class TestPersistentProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
         query.setMaxResults(100);
 
-        final QueryResult result = repo.queryEvents(query);
+        final QueryResult result = repo.queryEvents(query, createUser());
         assertEquals(20, result.getMatchingEvents().size());
 
         // Ensure index directories exists
@@ -1022,7 +1026,7 @@ public class TestPersistentProvenanceRepository {
         repo.purgeOldEvents();
         Thread.sleep(2000L);
 
-        final QueryResult newRecordSet = repo.queryEvents(query);
+        final QueryResult newRecordSet = repo.queryEvents(query, createUser());
         assertEquals(10, newRecordSet.getMatchingEvents().size());
 
         // Ensure that one index directory is gone
@@ -1030,6 +1034,291 @@ public class TestPersistentProvenanceRepository {
         assertEquals(1, indexDirs.length);
     }
 
+    @Test
+    public void testNotAuthorizedGetSpecificEvent() throws IOException {
+        final RepositoryConfiguration config = createConfiguration();
+        config.setMaxRecordLife(5, TimeUnit.MINUTES);
+        config.setMaxStorageCapacity(1024L * 1024L);
+        config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
+        config.setMaxEventFileCapacity(1024L * 1024L);
+        config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
+        config.setDesiredIndexSize(10); // force new index to be created for each rollover
+
+        final AccessDeniedException expectedException = new AccessDeniedException("Unit Test - Intentionally Thrown");
+        repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS) {
+            @Override
+            protected void authorize(ProvenanceEventRecord event, NiFiUser user) {
+                throw expectedException;
+            }
+        };
+
+        repo.initialize(getEventReporter(), null, null);
+
+        final String uuid = "00000000-0000-0000-0000-000000000000";
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "xyz");
+        attributes.put("xyz", "abc");
+        attributes.put("filename", "file-" + uuid);
+
+        final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
+        builder.setEventTime(System.currentTimeMillis());
+        builder.setEventType(ProvenanceEventType.RECEIVE);
+        builder.setTransitUri("nifi://unit-test");
+        builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
+        builder.setComponentId("1234");
+        builder.setComponentType("dummy processor");
+
+        for (int i = 0; i < 10; i++) {
+            attributes.put("uuid", "00000000-0000-0000-0000-00000000000" + i);
+            builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
+            builder.setEventTime(10L); // make sure the events are destroyed when we call purge
+            repo.registerEvent(builder.build());
+        }
+
+        repo.waitForRollover();
+
+        try {
+            repo.getEvent(0L, null);
+            Assert.fail("getEvent() did not throw an Exception");
+        } catch (final Exception e) {
+            Assert.assertSame(expectedException, e);
+        }
+    }
+
+    @Test
+    public void testNotAuthorizedGetEventRange() throws IOException {
+        final RepositoryConfiguration config = createConfiguration();
+        config.setMaxRecordLife(5, TimeUnit.MINUTES);
+        config.setMaxStorageCapacity(1024L * 1024L);
+        config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
+        config.setMaxEventFileCapacity(1024L * 1024L);
+        config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
+        config.setDesiredIndexSize(10); // force new index to be created for each rollover
+
+        repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS) {
+            @Override
+            public boolean isAuthorized(ProvenanceEventRecord event, NiFiUser user) {
+                return event.getEventId() > 2;
+            }
+        };
+
+        repo.initialize(getEventReporter(), null, null);
+
+        final String uuid = "00000000-0000-0000-0000-000000000000";
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "xyz");
+        attributes.put("xyz", "abc");
+        attributes.put("filename", "file-" + uuid);
+
+        final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
+        builder.setEventTime(System.currentTimeMillis());
+        builder.setEventType(ProvenanceEventType.RECEIVE);
+        builder.setTransitUri("nifi://unit-test");
+        builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
+        builder.setComponentId("1234");
+        builder.setComponentType("dummy processor");
+
+        for (int i = 0; i < 10; i++) {
+            attributes.put("uuid", "00000000-0000-0000-0000-00000000000" + i);
+            builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
+            builder.setEventTime(10L); // make sure the events are destroyed when we call purge
+            repo.registerEvent(builder.build());
+        }
+
+        repo.waitForRollover();
+
+        final List<ProvenanceEventRecord> events = repo.getEvents(0L, 10, null);
+
+        // Ensure that we gets events with ID's 3 through 10.
+        assertEquals(7, events.size());
+        final List<Long> eventIds = events.stream().map(event -> event.getEventId()).sorted().collect(Collectors.toList());
+        for (int i = 0; i < 7; i++) {
+            Assert.assertEquals(i + 3, eventIds.get(i).intValue());
+        }
+    }
+
+    @Test(timeout = 10000)
+    public void testNotAuthorizedQuery() throws IOException, InterruptedException {
+        final RepositoryConfiguration config = createConfiguration();
+        config.setMaxRecordLife(5, TimeUnit.MINUTES);
+        config.setMaxStorageCapacity(1024L * 1024L);
+        config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
+        config.setMaxEventFileCapacity(1024L * 1024L);
+        config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
+        config.setDesiredIndexSize(10); // force new index to be created for each rollover
+
+        repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS) {
+            @Override
+            public boolean isAuthorized(ProvenanceEventRecord event, NiFiUser user) {
+                return event.getEventId() > 2;
+            }
+        };
+
+        repo.initialize(getEventReporter(), null, null);
+
+        final String uuid = "00000000-0000-0000-0000-000000000000";
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "xyz");
+        attributes.put("xyz", "abc");
+        attributes.put("filename", "file-" + uuid);
+
+        final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
+        builder.setEventTime(System.currentTimeMillis());
+        builder.setEventType(ProvenanceEventType.RECEIVE);
+        builder.setTransitUri("nifi://unit-test");
+        builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
+        builder.setComponentId("1234");
+        builder.setComponentType("dummy processor");
+
+        for (int i = 0; i < 10; i++) {
+            attributes.put("uuid", "00000000-0000-0000-0000-00000000000" + i);
+            builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
+            builder.setEventTime(10L); // make sure the events are destroyed when we call purge
+            repo.registerEvent(builder.build());
+        }
+
+        repo.waitForRollover();
+
+        final Query query = new Query("1234");
+        query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.ComponentID, "1234"));
+        final QuerySubmission submission = repo.submitQuery(query, createUser());
+
+        final QueryResult result = submission.getResult();
+        while (!result.isFinished()) {
+            Thread.sleep(100L);
+        }
+
+        // Ensure that we gets events with ID's 3 through 10.
+        final List<ProvenanceEventRecord> events = result.getMatchingEvents();
+        assertEquals(7, events.size());
+        final List<Long> eventIds = events.stream().map(event -> event.getEventId()).sorted().collect(Collectors.toList());
+        for (int i = 0; i < 7; i++) {
+            Assert.assertEquals(i + 3, eventIds.get(i).intValue());
+        }
+    }
+
+
+    @Test(timeout = 1000000)
+    public void testNotAuthorizedLineage() throws IOException, InterruptedException {
+        final RepositoryConfiguration config = createConfiguration();
+        config.setMaxRecordLife(5, TimeUnit.MINUTES);
+        config.setMaxStorageCapacity(1024L * 1024L);
+        config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
+        config.setMaxEventFileCapacity(1024L * 1024L);
+        config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
+        config.setDesiredIndexSize(10); // force new index to be created for each rollover
+
+        repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS) {
+            @Override
+            public boolean isAuthorized(ProvenanceEventRecord event, NiFiUser user) {
+                return event.getEventType() != ProvenanceEventType.ATTRIBUTES_MODIFIED;
+            }
+        };
+
+        repo.initialize(getEventReporter(), null, null);
+
+        final String uuid = "00000000-0000-0000-0000-000000000000";
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "xyz");
+        attributes.put("xyz", "abc");
+        attributes.put("filename", "file-" + uuid);
+        attributes.put("uuid", uuid);
+
+        final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
+        builder.setEventTime(System.currentTimeMillis());
+        builder.setEventType(ProvenanceEventType.RECEIVE);
+        builder.setTransitUri("nifi://unit-test");
+        builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
+        builder.setComponentId("1234");
+        builder.setComponentType("dummy processor");
+        builder.setEventTime(10L); // make sure the events are destroyed when we call purge
+
+        builder.fromFlowFile(createFlowFile(1, 3000L, attributes));
+        repo.registerEvent(builder.build());
+
+        builder.setEventType(ProvenanceEventType.CONTENT_MODIFIED);
+        builder.fromFlowFile(createFlowFile(2, 2000L, attributes));
+        repo.registerEvent(builder.build());
+
+        builder.setEventType(ProvenanceEventType.CONTENT_MODIFIED);
+        builder.fromFlowFile(createFlowFile(3, 2000L, attributes));
+        repo.registerEvent(builder.build());
+
+        builder.setEventType(ProvenanceEventType.ATTRIBUTES_MODIFIED);
+        attributes.put("new-attr", "yes");
+        builder.fromFlowFile(createFlowFile(4, 2000L, attributes));
+        repo.registerEvent(builder.build());
+
+        final Map<String, String> childAttributes = new HashMap<>(attributes);
+        childAttributes.put("uuid", "00000000-0000-0000-0000-000000000001");
+        builder.setEventType(ProvenanceEventType.FORK);
+        builder.fromFlowFile(createFlowFile(4, 2000L, attributes));
+        builder.addChildFlowFile(createFlowFile(5, 2000L, childAttributes));
+        builder.addParentFlowFile(createFlowFile(4, 2000L, attributes));
+        repo.registerEvent(builder.build());
+
+        builder.setEventType(ProvenanceEventType.ATTRIBUTES_MODIFIED);
+        builder.fromFlowFile(createFlowFile(6, 2000L, childAttributes));
+        repo.registerEvent(builder.build());
+
+        builder.setEventType(ProvenanceEventType.DROP);
+        builder.fromFlowFile(createFlowFile(6, 2000L, childAttributes));
+        repo.registerEvent(builder.build());
+
+        repo.waitForRollover();
+
+        final AsyncLineageSubmission originalLineage = repo.submitLineageComputation(uuid, createUser());
+
+        final StandardLineageResult result = originalLineage.getResult();
+        while (!result.isFinished()) {
+            Thread.sleep(100L);
+        }
+
+        final List<LineageNode> lineageNodes = result.getNodes();
+        assertEquals(6, lineageNodes.size());
+
+        assertEquals(1, lineageNodes.stream().map(node -> node.getNodeType()).filter(t -> t == LineageNodeType.FLOWFILE_NODE).count());
+        assertEquals(5, lineageNodes.stream().map(node -> node.getNodeType()).filter(t -> t == LineageNodeType.PROVENANCE_EVENT_NODE).count());
+
+        final Set<EventNode> eventNodes = lineageNodes.stream()
+            .filter(node -> node.getNodeType() == LineageNodeType.PROVENANCE_EVENT_NODE)
+            .map(node -> (EventNode) node)
+            .collect(Collectors.toSet());
+
+        final Map<ProvenanceEventType, List<EventNode>> nodesByType = eventNodes.stream().collect(Collectors.groupingBy(EventNode::getEventType));
+        assertEquals(1, nodesByType.get(ProvenanceEventType.RECEIVE).size());
+        assertEquals(2, nodesByType.get(ProvenanceEventType.CONTENT_MODIFIED).size());
+        assertEquals(1, nodesByType.get(ProvenanceEventType.FORK).size());
+
+        assertEquals(1, nodesByType.get(ProvenanceEventType.UNKNOWN).size());
+        assertNull(nodesByType.get(ProvenanceEventType.ATTRIBUTES_MODIFIED));
+
+        // Test filtering on expandChildren
+        final AsyncLineageSubmission expandChild = repo.submitExpandChildren(4L, createUser());
+        final StandardLineageResult expandChildResult = expandChild.getResult();
+        while (!expandChildResult.isFinished()) {
+            Thread.sleep(100L);
+        }
+
+        final List<LineageNode> expandChildNodes = expandChildResult.getNodes();
+        assertEquals(4, expandChildNodes.size());
+
+        assertEquals(1, expandChildNodes.stream().map(node -> node.getNodeType()).filter(t -> t == LineageNodeType.FLOWFILE_NODE).count());
+        assertEquals(3, expandChildNodes.stream().map(node -> node.getNodeType()).filter(t -> t == LineageNodeType.PROVENANCE_EVENT_NODE).count());
+
+        final Set<EventNode> childEventNodes = expandChildNodes.stream()
+            .filter(node -> node.getNodeType() == LineageNodeType.PROVENANCE_EVENT_NODE)
+            .map(node -> (EventNode) node)
+            .collect(Collectors.toSet());
+
+        final Map<ProvenanceEventType, List<EventNode>> childNodesByType = childEventNodes.stream().collect(Collectors.groupingBy(EventNode::getEventType));
+        assertEquals(1, childNodesByType.get(ProvenanceEventType.FORK).size());
+        assertEquals(1, childNodesByType.get(ProvenanceEventType.DROP).size());
+        assertEquals(1, childNodesByType.get(ProvenanceEventType.UNKNOWN).size());
+        assertNull(childNodesByType.get(ProvenanceEventType.ATTRIBUTES_MODIFIED));
+    }
+
+
 
     @Test
     public void testBackPressure() throws IOException, InterruptedException {
@@ -1045,7 +1334,7 @@ public class TestPersistentProvenanceRepository {
                 return journalCountRef.get();
             }
         };
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
@@ -1103,7 +1392,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
         config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final String uuid = "00000000-0000-0000-0000-000000000000";
         final Map<String, String> attributes = new HashMap<>();
@@ -1170,7 +1459,7 @@ public class TestPersistentProvenanceRepository {
         final RepositoryConfiguration config = createConfiguration();
         config.setMaxEventFileLife(3, TimeUnit.SECONDS);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
 
@@ -1221,7 +1510,7 @@ public class TestPersistentProvenanceRepository {
         config.setMaxAttributeChars(50);
         config.setMaxEventFileLife(3, TimeUnit.SECONDS);
         repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("75chars", "123456789012345678901234567890123456789012345678901234567890123456789012345");
@@ -1240,7 +1529,7 @@ public class TestPersistentProvenanceRepository {
         repo.registerEvent(record);
         repo.waitForRollover();
 
-        final ProvenanceEventRecord retrieved = repo.getEvent(0L);
+        final ProvenanceEventRecord retrieved = repo.getEvent(0L, null);
         assertNotNull(retrieved);
         assertEquals("12345678-0000-0000-0000-012345678912", retrieved.getAttributes().get("uuid"));
         assertEquals("12345678901234567890123456789012345678901234567890", retrieved.getAttributes().get("75chars"));
@@ -1269,7 +1558,7 @@ public class TestPersistentProvenanceRepository {
         };
 
         // initialize with our event reporter
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         // create some events in the journal files.
         final Map<String, String> attributes = new HashMap<>();
@@ -1346,7 +1635,7 @@ public class TestPersistentProvenanceRepository {
                 return spiedWriters;
             }
         };
-        repo.initialize(getEventReporter());
+        repo.initialize(getEventReporter(), null, null);
 
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("75chars", "123456789012345678901234567890123456789012345678901234567890123456789012345");
@@ -1407,7 +1696,7 @@ public class TestPersistentProvenanceRepository {
         };
 
         try {
-            recoveryRepo.initialize(getEventReporter());
+            recoveryRepo.initialize(getEventReporter(), null, null);
         } finally {
             recoveryRepo.close();
         }
@@ -1437,4 +1726,29 @@ public class TestPersistentProvenanceRepository {
             return severity;
         }
     }
+
+    private NiFiUser createUser() {
+        return new NiFiUser() {
+            @Override
+            public String getIdentity() {
+                return "unit-test";
+            }
+
+            @Override
+            public String getUserName() {
+                return "Unit Test";
+            }
+
+            @Override
+            public NiFiUser getChain() {
+                return null;
+            }
+
+            @Override
+            public boolean isAnonymous() {
+                return false;
+            }
+        };
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/main/java/org/apache/nifi/provenance/VolatileProvenanceRepository.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/main/java/org/apache/nifi/provenance/VolatileProvenanceRepository.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/main/java/org/apache/nifi/provenance/VolatileProvenanceRepository.java
index f4f9d12..888f55a 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/main/java/org/apache/nifi/provenance/VolatileProvenanceRepository.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/main/java/org/apache/nifi/provenance/VolatileProvenanceRepository.java
@@ -37,6 +37,13 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Pattern;
 
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.flowfile.attributes.CoreAttributes;
 import org.apache.nifi.processor.DataUnit;
@@ -55,6 +62,7 @@ import org.apache.nifi.util.RingBuffer;
 import org.apache.nifi.util.RingBuffer.Filter;
 import org.apache.nifi.util.RingBuffer.ForEachEvaluator;
 import org.apache.nifi.util.RingBuffer.IterationDirection;
+import org.apache.nifi.web.ResourceNotFoundException;
 
 public class VolatileProvenanceRepository implements ProvenanceEventRepository {
 
@@ -75,6 +83,9 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     private final AtomicLong idGenerator = new AtomicLong(0L);
     private final AtomicBoolean initialized = new AtomicBoolean(false);
 
+    private Authorizer authorizer;  // effectively final
+    private ProvenanceAuthorizableFactory resourceFactory;  // effectively final
+
     public VolatileProvenanceRepository() {
         final NiFiProperties properties = NiFiProperties.getInstance();
 
@@ -103,11 +114,14 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
-    public void initialize(final EventReporter eventReporter) {
+    public void initialize(final EventReporter eventReporter, final Authorizer authorizer, final ProvenanceAuthorizableFactory resourceFactory) throws IOException {
         if (initialized.getAndSet(true)) {
             return;
         }
 
+        this.authorizer = authorizer;
+        this.resourceFactory = resourceFactory;
+
         scheduledExecService.scheduleWithFixedDelay(new RemoveExpiredQueryResults(), 30L, 30L, TimeUnit.SECONDS);
     }
 
@@ -131,9 +145,18 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
 
     @Override
     public List<ProvenanceEventRecord> getEvents(final long firstRecordId, final int maxRecords) throws IOException {
+        return getEvents(firstRecordId, maxRecords, null);
+    }
+
+    @Override
+    public List<ProvenanceEventRecord> getEvents(final long firstRecordId, final int maxRecords, final NiFiUser user) throws IOException {
         return ringBuffer.getSelectedElements(new Filter<ProvenanceEventRecord>() {
             @Override
             public boolean select(final ProvenanceEventRecord value) {
+                if (user != null && !isAuthorized(value, user)) {
+                    return false;
+                }
+
                 return value.getEventId() >= firstRecordId;
             }
         }, maxRecords);
@@ -155,8 +178,7 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
         return records.isEmpty() ? null : records.get(0);
     }
 
-    @Override
-    public ProvenanceEventRecord getEvent(final long id) {
+    private ProvenanceEventRecord getEvent(final long id) {
         final List<ProvenanceEventRecord> records = ringBuffer.getSelectedElements(new Filter<ProvenanceEventRecord>() {
             @Override
             public boolean select(final ProvenanceEventRecord event) {
@@ -168,6 +190,17 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
+    public ProvenanceEventRecord getEvent(final long id, final NiFiUser user) {
+        final ProvenanceEventRecord event = getEvent(id);
+        if (event == null) {
+            return null;
+        }
+
+        authorize(event, user);
+        return event;
+    }
+
+    @Override
     public void close() throws IOException {
         queryExecService.shutdownNow();
         scheduledExecService.shutdown();
@@ -183,8 +216,8 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
         return searchableAttributes;
     }
 
-    public QueryResult queryEvents(final Query query) throws IOException {
-        final QuerySubmission submission = submitQuery(query);
+    public QueryResult queryEvents(final Query query, final NiFiUser user) throws IOException {
+        final QuerySubmission submission = submitQuery(query, user);
         final QueryResult result = submission.getResult();
         while (!result.isFinished()) {
             try {
@@ -200,10 +233,40 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
         return result;
     }
 
-    private Filter<ProvenanceEventRecord> createFilter(final Query query) {
+
+    public boolean isAuthorized(final ProvenanceEventRecord event, final NiFiUser user) {
+        if (authorizer == null) {
+            return true;
+        }
+
+        final Authorizable eventAuthorizable;
+        try {
+            eventAuthorizable = resourceFactory.createProvenanceAuthorizable(event.getComponentId());
+        } catch (final ResourceNotFoundException rnfe) {
+            return false;
+        }
+
+        final AuthorizationResult result = eventAuthorizable.checkAuthorization(authorizer, RequestAction.READ, user);
+        return Result.Approved.equals(result.getResult());
+    }
+
+    protected void authorize(final ProvenanceEventRecord event, final NiFiUser user) {
+        if (authorizer == null) {
+            return;
+        }
+
+        final Authorizable eventAuthorizable = resourceFactory.createProvenanceAuthorizable(event.getComponentId());
+        eventAuthorizable.authorize(authorizer, RequestAction.READ, user);
+    }
+
+    private Filter<ProvenanceEventRecord> createFilter(final Query query, final NiFiUser user) {
         return new Filter<ProvenanceEventRecord>() {
             @Override
             public boolean select(final ProvenanceEventRecord event) {
+                if (!isAuthorized(event, user)) {
+                    return false;
+                }
+
                 if (query.getStartDate() != null && query.getStartDate().getTime() > event.getEventTime()) {
                     return false;
                 }
@@ -348,36 +411,51 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
-    public QuerySubmission submitQuery(final Query query) {
+    public QuerySubmission submitQuery(final Query query, final NiFiUser user) {
         if (query.getEndDate() != null && query.getStartDate() != null && query.getStartDate().getTime() > query.getEndDate().getTime()) {
             throw new IllegalArgumentException("Query End Time cannot be before Query Start Time");
         }
 
         if (query.getSearchTerms().isEmpty() && query.getStartDate() == null && query.getEndDate() == null) {
-            final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1);
-            queryExecService.submit(new QueryRunnable(ringBuffer, createFilter(query), query.getMaxResults(), result));
+            final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1, user.getIdentity());
+            queryExecService.submit(new QueryRunnable(ringBuffer, createFilter(query, user), query.getMaxResults(), result));
             querySubmissionMap.put(query.getIdentifier(), result);
             return result;
         }
 
-        final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1);
+        final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1, user.getIdentity());
         querySubmissionMap.put(query.getIdentifier(), result);
-        queryExecService.submit(new QueryRunnable(ringBuffer, createFilter(query), query.getMaxResults(), result));
+        queryExecService.submit(new QueryRunnable(ringBuffer, createFilter(query, user), query.getMaxResults(), result));
 
         return result;
     }
 
     @Override
-    public QuerySubmission retrieveQuerySubmission(final String queryIdentifier) {
-        return querySubmissionMap.get(queryIdentifier);
+    public QuerySubmission retrieveQuerySubmission(final String queryIdentifier, final NiFiUser user) {
+        final QuerySubmission submission = querySubmissionMap.get(queryIdentifier);
+        final String userId = submission.getSubmitterIdentity();
+
+        if (user == null && userId == null) {
+            return submission;
+        }
+
+        if (user == null) {
+            throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because no user id was provided");
+        }
+
+        if (userId == null || userId.equals(user.getIdentity())) {
+            return submission;
+        }
+
+        throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because " + user.getIdentity() + " is not the user who submitted the request");
     }
 
-    public Lineage computeLineage(final String flowFileUUID) throws IOException {
-        return computeLineage(Collections.<String>singleton(flowFileUUID), LineageComputationType.FLOWFILE_LINEAGE, null);
+    public Lineage computeLineage(final String flowFileUUID, final NiFiUser user) throws IOException {
+        return computeLineage(Collections.<String> singleton(flowFileUUID), user, LineageComputationType.FLOWFILE_LINEAGE, null);
     }
 
-    private Lineage computeLineage(final Collection<String> flowFileUuids, final LineageComputationType computationType, final Long eventId) throws IOException {
-        final AsyncLineageSubmission submission = submitLineageComputation(flowFileUuids, computationType, eventId);
+    private Lineage computeLineage(final Collection<String> flowFileUuids, final NiFiUser user, final LineageComputationType computationType, final Long eventId) throws IOException {
+        final AsyncLineageSubmission submission = submitLineageComputation(flowFileUuids, user, computationType, eventId);
         final StandardLineageResult result = submission.getResult();
         while (!result.isFinished()) {
             try {
@@ -394,13 +472,28 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
-    public AsyncLineageSubmission submitLineageComputation(final String flowFileUuid) {
-        return submitLineageComputation(Collections.singleton(flowFileUuid), LineageComputationType.FLOWFILE_LINEAGE, null);
+    public AsyncLineageSubmission submitLineageComputation(final String flowFileUuid, final NiFiUser user) {
+        return submitLineageComputation(Collections.singleton(flowFileUuid), user, LineageComputationType.FLOWFILE_LINEAGE, null);
     }
 
     @Override
-    public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier) {
-        return lineageSubmissionMap.get(lineageIdentifier);
+    public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier, final NiFiUser user) {
+        final ComputeLineageSubmission submission = lineageSubmissionMap.get(lineageIdentifier);
+        final String userId = submission.getSubmitterIdentity();
+
+        if (user == null && userId == null) {
+            return submission;
+        }
+
+        if (user == null) {
+            throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because no user id was provided");
+        }
+
+        if (userId == null || userId.equals(user.getIdentity())) {
+            return submission;
+        }
+
+        throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because " + user.getIdentity() + " is not the user who submitted the request");
     }
 
     public Lineage expandSpawnEventParents(String identifier) throws IOException {
@@ -408,10 +501,12 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
-    public ComputeLineageSubmission submitExpandParents(final long eventId) {
-        final ProvenanceEventRecord event = getEvent(eventId);
+    public ComputeLineageSubmission submitExpandParents(final long eventId, final NiFiUser user) {
+        final String userId = user.getIdentity();
+
+        final ProvenanceEventRecord event = getEvent(eventId, user);
         if (event == null) {
-            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String>emptyList(), 1);
+            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String> emptyList(), 1, userId);
             lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
             submission.getResult().update(Collections.<ProvenanceEventRecord>emptyList());
             return submission;
@@ -422,9 +517,9 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
             case FORK:
             case REPLAY:
             case CLONE:
-                return submitLineageComputation(event.getParentUuids(), LineageComputationType.EXPAND_PARENTS, eventId);
+                return submitLineageComputation(event.getParentUuids(), user, LineageComputationType.EXPAND_PARENTS, eventId);
             default: {
-                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String>emptyList(), 1);
+                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String> emptyList(), 1, userId);
                 lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                 submission.getResult().setError("Event ID " + eventId + " indicates an event of type " + event.getEventType() + " so its parents cannot be expanded");
                 return submission;
@@ -437,10 +532,12 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
     }
 
     @Override
-    public ComputeLineageSubmission submitExpandChildren(final long eventId) {
-        final ProvenanceEventRecord event = getEvent(eventId);
+    public ComputeLineageSubmission submitExpandChildren(final long eventId, final NiFiUser user) {
+        final String userId = user.getIdentity();
+
+        final ProvenanceEventRecord event = getEvent(eventId, user);
         if (event == null) {
-            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
             lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
             submission.getResult().update(Collections.<ProvenanceEventRecord>emptyList());
             return submission;
@@ -451,9 +548,9 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
             case FORK:
             case REPLAY:
             case CLONE:
-                return submitLineageComputation(event.getChildUuids(), LineageComputationType.EXPAND_CHILDREN, eventId);
+                return submitLineageComputation(event.getChildUuids(), user, LineageComputationType.EXPAND_CHILDREN, eventId);
             default: {
-                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
                 lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                 submission.getResult().setError("Event ID " + eventId + " indicates an event of type " + event.getEventType() + " so its children cannot be expanded");
                 return submission;
@@ -461,13 +558,18 @@ public class VolatileProvenanceRepository implements ProvenanceEventRepository {
         }
     }
 
-    private AsyncLineageSubmission submitLineageComputation(final Collection<String> flowFileUuids, final LineageComputationType computationType, final Long eventId) {
-        final AsyncLineageSubmission result = new AsyncLineageSubmission(computationType, eventId, flowFileUuids, 1);
+    private AsyncLineageSubmission submitLineageComputation(final Collection<String> flowFileUuids, final NiFiUser user, final LineageComputationType computationType, final Long eventId) {
+        final String userId = user.getIdentity();
+        final AsyncLineageSubmission result = new AsyncLineageSubmission(computationType, eventId, flowFileUuids, 1, userId);
         lineageSubmissionMap.put(result.getLineageIdentifier(), result);
 
         final Filter<ProvenanceEventRecord> filter = new Filter<ProvenanceEventRecord>() {
             @Override
             public boolean select(final ProvenanceEventRecord event) {
+                if (user != null && !isAuthorized(event, user)) {
+                    return false;
+                }
+
                 if (flowFileUuids.contains(event.getFlowFileUuid())) {
                     return true;
                 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/test/java/org/apache/nifi/provenance/TestVolatileProvenanceRepository.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/test/java/org/apache/nifi/provenance/TestVolatileProvenanceRepository.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/test/java/org/apache/nifi/provenance/TestVolatileProvenanceRepository.java
index 3c3e401..d35ceac 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/test/java/org/apache/nifi/provenance/TestVolatileProvenanceRepository.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-volatile-provenance-repository/src/test/java/org/apache/nifi/provenance/TestVolatileProvenanceRepository.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.provenance.search.Query;
 import org.apache.nifi.provenance.search.QuerySubmission;
@@ -70,7 +71,7 @@ public class TestVolatileProvenanceRepository {
         assertEquals(10, retrieved.size());
         for (int i = 0; i < 10; i++) {
             final ProvenanceEventRecord recovered = retrieved.get(i);
-            assertEquals((long) i, recovered.getEventId());
+            assertEquals(i, recovered.getEventId());
             assertEquals("nifi://unit-test", recovered.getTransitUri());
             assertEquals(ProvenanceEventType.RECEIVE, recovered.getEventType());
             assertEquals(attributes, recovered.getAttributes());
@@ -108,7 +109,7 @@ public class TestVolatileProvenanceRepository {
         query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
         query.setMaxResults(100);
 
-        final QuerySubmission submission = repo.submitQuery(query);
+        final QuerySubmission submission = repo.submitQuery(query, createUser());
         while (!submission.getResult().isFinished()) {
             Thread.sleep(100L);
         }
@@ -175,4 +176,27 @@ public class TestVolatileProvenanceRepository {
         };
     }
 
+    private NiFiUser createUser() {
+        return new NiFiUser() {
+            @Override
+            public String getIdentity() {
+                return "unit-test";
+            }
+
+            @Override
+            public String getUserName() {
+                return "Unit Test";
+            }
+
+            @Override
+            public NiFiUser getChain() {
+                return null;
+            }
+
+            @Override
+            public boolean isAnonymous() {
+                return false;
+            }
+        };
+    }
 }


[3/4] nifi git commit: NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
index 901f83d..f263ac6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
@@ -134,7 +134,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 // authorize access
                 serviceFacade.authorizeAccess(lookup -> {
                     final Authorizable authorizable = lookup.getProcessor(requestContext.getId());
-                    authorizable.authorize(authorizer, RequestAction.WRITE);
+                    authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 });
 
                 componentType = Component.Processor;
@@ -143,7 +143,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 // authorize access
                 serviceFacade.authorizeAccess(lookup -> {
                     final Authorizable authorizable = lookup.getControllerService(requestContext.getId());
-                    authorizable.authorize(authorizer, RequestAction.WRITE);
+                    authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 });
 
                 componentType = Component.ControllerService;
@@ -152,7 +152,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 // authorize access
                 serviceFacade.authorizeAccess(lookup -> {
                     final Authorizable authorizable = lookup.getReportingTask(requestContext.getId());
-                    authorizable.authorize(authorizer, RequestAction.WRITE);
+                    authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 });
 
                 componentType = Component.ReportingTask;
@@ -322,7 +322,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getProcessor(id);
-                authorizable.authorize(authorizer, RequestAction.READ);
+                authorizable.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
             });
 
             final ProcessorDTO processor;
@@ -374,7 +374,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getProcessor(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
 
             final ProcessorDTO processor;
@@ -510,7 +510,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getControllerService(id);
-                authorizable.authorize(authorizer, RequestAction.READ);
+                authorizable.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
             });
 
             // if the lookup has the service that means we are either a node or
@@ -568,7 +568,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getControllerService(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
 
             final ControllerServiceDTO controllerService;
@@ -678,7 +678,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getReportingTask(id);
-                authorizable.authorize(authorizer, RequestAction.READ);
+                authorizable.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
             });
 
             // if the provider has the service that means we are either a node or
@@ -736,7 +736,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable authorizable = lookup.getReportingTask(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
 
             final ReportingTaskDTO reportingTask;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
index 6ccbeee..dd537cd 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessPolicyResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.coordination.ClusterCoordinator;
 import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
 import org.apache.nifi.util.NiFiProperties;
@@ -205,7 +206,7 @@ public class AccessPolicyResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable accessPolicies = lookup.getAccessPoliciesAuthorizable();
-                accessPolicies.authorize(authorizer, RequestAction.WRITE);
+                accessPolicies.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -270,7 +271,7 @@ public class AccessPolicyResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable accessPolicy = lookup.getAccessPolicyAuthorizable(id);
-            accessPolicy.authorize(authorizer, RequestAction.READ);
+            accessPolicy.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the access policy
@@ -347,7 +348,7 @@ public class AccessPolicyResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     Authorizable authorizable  = lookup.getAccessPolicyAuthorizable(id);
-                    authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 },
                 null,
                 () -> {
@@ -422,7 +423,7 @@ public class AccessPolicyResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     final Authorizable accessPolicy = lookup.getAccessPolicyAuthorizable(id);
-                    accessPolicy.authorize(authorizer, RequestAction.READ);
+                accessPolicy.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
                 },
                 () -> {
                 },

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
index cb11f90..262e274 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
@@ -424,7 +424,7 @@ public abstract class ApplicationResource {
      * @param action     action
      */
     protected void authorizeSnippet(final Snippet snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action) {
-        final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action);
+        final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
 
         snippet.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(authorize);
         snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
@@ -444,7 +444,7 @@ public abstract class ApplicationResource {
      * @param action     action
      */
     protected void authorizeSnippet(final SnippetDTO snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action) {
-        final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action);
+        final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
 
         snippet.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(authorize);
         snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
index 67a76fd..6cd1dea 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
@@ -191,7 +192,7 @@ public class ConnectionResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable conn = lookup.getConnection(id);
-            conn.authorize(authorizer, RequestAction.READ);
+            conn.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the specified relationship
@@ -270,7 +271,7 @@ public class ConnectionResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getConnection(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateConnection(connection),
             () -> {
@@ -345,7 +346,7 @@ public class ConnectionResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable conn = lookup.getConnection(id);
-                conn.authorize(authorizer, RequestAction.WRITE);
+                conn.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteConnection(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
index b79ee62..10cf9bf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
@@ -16,16 +16,34 @@
  */
 package org.apache.nifi.web.api;
 
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.controller.ScheduledState;
 import org.apache.nifi.controller.service.ControllerServiceState;
 import org.apache.nifi.ui.extension.UiExtension;
@@ -47,27 +65,12 @@ import org.apache.nifi.web.api.request.LongParameter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+import com.wordnik.swagger.annotations.Authorization;
 
 /**
  * RESTful endpoint for managing a Controller Service.
@@ -192,7 +195,7 @@ public class ControllerServiceResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable controllerService = lookup.getControllerService(id);
-            controllerService.authorize(authorizer, RequestAction.READ);
+            controllerService.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the controller service
@@ -256,7 +259,7 @@ public class ControllerServiceResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable controllerService = lookup.getControllerService(id);
-            controllerService.authorize(authorizer, RequestAction.READ);
+            controllerService.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the property descriptor
@@ -311,7 +314,7 @@ public class ControllerServiceResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable controllerService = lookup.getControllerService(id);
-            controllerService.authorize(authorizer, RequestAction.WRITE);
+            controllerService.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the component state
@@ -370,7 +373,7 @@ public class ControllerServiceResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processor = lookup.getControllerService(id);
-                processor.authorize(authorizer, RequestAction.WRITE);
+                processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -431,7 +434,7 @@ public class ControllerServiceResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable controllerService = lookup.getControllerService(id);
-            controllerService.authorize(authorizer, RequestAction.READ);
+            controllerService.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the controller service
@@ -540,7 +543,7 @@ public class ControllerServiceResource extends ApplicationResource {
             lookup -> {
                 referencingRevisions.entrySet().stream().forEach(e -> {
                     final Authorizable controllerService = lookup.getControllerServiceReferencingComponent(id, e.getKey());
-                    controllerService.authorize(authorizer, RequestAction.WRITE);
+                    controllerService.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 });
             },
             () -> serviceFacade.verifyUpdateControllerServiceReferencingComponents(updateReferenceRequest.getId(), scheduledState, controllerServiceState),
@@ -621,7 +624,7 @@ public class ControllerServiceResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getControllerService(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateControllerService(requestControllerServiceDTO),
             () -> {
@@ -696,7 +699,7 @@ public class ControllerServiceResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable controllerService = lookup.getControllerService(id);
-                controllerService.authorize(authorizer, RequestAction.WRITE);
+                controllerService.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteControllerService(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowFileQueueResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowFileQueueResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowFileQueueResource.java
index 2956bb5..2be19e6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowFileQueueResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowFileQueueResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.stream.io.StreamUtils;
@@ -177,7 +178,7 @@ public class FlowFileQueueResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable connection = lookup.getConnection(connectionId);
-            connection.authorize(authorizer, RequestAction.WRITE);
+            connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the flowfile
@@ -265,7 +266,7 @@ public class FlowFileQueueResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable connection = lookup.getConnection(connectionId);
-            connection.authorize(authorizer, RequestAction.WRITE);
+            connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the uri of the request
@@ -344,7 +345,7 @@ public class FlowFileQueueResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable connection = lookup.getConnection(id);
-                connection.authorize(authorizer, RequestAction.WRITE);
+                connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -415,7 +416,7 @@ public class FlowFileQueueResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable connection = lookup.getConnection(connectionId);
-            connection.authorize(authorizer, RequestAction.WRITE);
+            connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the listing request
@@ -481,7 +482,7 @@ public class FlowFileQueueResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable connection = lookup.getConnection(connectionId);
-                connection.authorize(authorizer, RequestAction.WRITE);
+                connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -551,7 +552,7 @@ public class FlowFileQueueResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable connection = lookup.getConnection(id);
-                connection.authorize(authorizer, RequestAction.WRITE);
+                connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -621,7 +622,7 @@ public class FlowFileQueueResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable connection = lookup.getConnection(connectionId);
-            connection.authorize(authorizer, RequestAction.WRITE);
+            connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the drop request
@@ -687,7 +688,7 @@ public class FlowFileQueueResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable connection = lookup.getConnection(connectionId);
-                connection.authorize(authorizer, RequestAction.WRITE);
+                connection.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
index 765933c..5c9bd9a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
@@ -16,13 +16,29 @@
  */
 package org.apache.nifi.web.api;
 
-import com.sun.jersey.api.core.ResourceContext;
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AccessDeniedException;
 import org.apache.nifi.authorization.AuthorizationRequest;
@@ -96,27 +112,13 @@ import org.apache.nifi.web.api.request.DateTimeParameter;
 import org.apache.nifi.web.api.request.IntegerParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
+import com.sun.jersey.api.core.ResourceContext;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+import com.wordnik.swagger.annotations.Authorization;
 
 /**
  * RESTful endpoint for managing a Flow.
@@ -661,7 +663,7 @@ public class FlowResource extends ApplicationResource {
                 // ensure authorized for each processor we will attempt to schedule
                 group.findAllProcessors().stream()
                     .filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PROCESSORS : ProcessGroup.UNSCHEDULABLE_PROCESSORS)
-                    .filter(processor -> processor.isAuthorized(authorizer, RequestAction.WRITE))
+                    .filter(processor -> processor.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
                     .forEach(processor -> {
                         componentIds.add(processor.getIdentifier());
                     });
@@ -669,7 +671,7 @@ public class FlowResource extends ApplicationResource {
                 // ensure authorized for each input port we will attempt to schedule
                 group.findAllInputPorts().stream()
                     .filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
-                    .filter(inputPort -> inputPort.isAuthorized(authorizer, RequestAction.WRITE))
+                    .filter(inputPort -> inputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
                     .forEach(inputPort -> {
                         componentIds.add(inputPort.getIdentifier());
                     });
@@ -677,7 +679,7 @@ public class FlowResource extends ApplicationResource {
                 // ensure authorized for each output port we will attempt to schedule
                 group.findAllOutputPorts().stream()
                     .filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
-                    .filter(outputPort -> outputPort.isAuthorized(authorizer, RequestAction.WRITE))
+                    .filter(outputPort -> outputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
                     .forEach(outputPort -> {
                         componentIds.add(outputPort.getIdentifier());
                     });
@@ -713,7 +715,7 @@ public class FlowResource extends ApplicationResource {
                 // ensure access to every component being scheduled
                 componentsToSchedule.keySet().forEach(componentId -> {
                     final Authorizable connectable = lookup.getConnectable(componentId);
-                    connectable.authorize(authorizer, RequestAction.WRITE);
+                    connectable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 });
             },
             () -> serviceFacade.verifyScheduleComponents(id, state, componentRevisions.keySet()),

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
index de2179c..51e8d7b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.FunnelDTO;
@@ -153,7 +154,7 @@ public class FunnelResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable funnel = lookup.getFunnel(id);
-            funnel.authorize(authorizer, RequestAction.READ);
+            funnel.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the funnel
@@ -230,7 +231,7 @@ public class FunnelResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getFunnel(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             null,
             () -> {
@@ -305,7 +306,7 @@ public class FunnelResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable funnel = lookup.getFunnel(id);
-                funnel.authorize(authorizer, RequestAction.WRITE);
+                funnel.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteFunnel(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
index 53e11ba..997838e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.PortDTO;
@@ -153,7 +154,7 @@ public class InputPortResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable inputPort = lookup.getInputPort(id);
-            inputPort.authorize(authorizer, RequestAction.READ);
+            inputPort.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the port
@@ -230,7 +231,7 @@ public class InputPortResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getInputPort(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateInputPort(requestPortDTO),
             () -> {
@@ -302,7 +303,7 @@ public class InputPortResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable inputPort = lookup.getInputPort(id);
-                inputPort.authorize(authorizer, RequestAction.WRITE);
+                inputPort.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteInputPort(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
index f21882b..f1ec506 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.LabelDTO;
@@ -153,7 +154,7 @@ public class LabelResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable label = lookup.getLabel(id);
-            label.authorize(authorizer, RequestAction.READ);
+            label.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the label
@@ -230,7 +231,7 @@ public class LabelResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable  = lookup.getLabel(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             null,
             () -> {
@@ -302,7 +303,7 @@ public class LabelResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable label = lookup.getLabel(id);
-                label.authorize(authorizer, RequestAction.WRITE);
+                label.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             null,
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
index bfaed4b..c99896c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.PortDTO;
@@ -153,7 +154,7 @@ public class OutputPortResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable outputPort = lookup.getOutputPort(id);
-            outputPort.authorize(authorizer, RequestAction.READ);
+            outputPort.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the port
@@ -230,7 +231,7 @@ public class OutputPortResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getOutputPort(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateOutputPort(requestPortDTO),
             () -> {
@@ -302,7 +303,7 @@ public class OutputPortResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable outputPort = lookup.getOutputPort(id);
-                outputPort.authorize(authorizer, RequestAction.WRITE);
+                outputPort.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteOutputPort(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
index b6671b2..48c241c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
@@ -16,18 +16,41 @@
  */
 package org.apache.nifi.web.api;
 
-import com.sun.jersey.api.core.ResourceContext;
-import com.sun.jersey.multipart.FormDataParam;
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.controller.Snippet;
 import org.apache.nifi.web.AuthorizableLookup;
 import org.apache.nifi.web.NiFiServiceFacade;
@@ -65,34 +88,14 @@ import org.apache.nifi.web.api.request.LongParameter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.HttpMethod;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.stream.StreamSource;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import com.sun.jersey.api.core.ResourceContext;
+import com.sun.jersey.multipart.FormDataParam;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+import com.wordnik.swagger.annotations.Authorization;
 
 /**
  * RESTful endpoint for managing a Group.
@@ -237,7 +240,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get this process group contents
@@ -318,7 +321,7 @@ public class ProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getProcessGroup(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             null,
             () -> {
@@ -391,7 +394,7 @@ public class ProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(id);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteProcessGroup(id),
             () -> {
@@ -473,7 +476,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -535,7 +538,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the process groups
@@ -633,7 +636,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -696,7 +699,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the processors
@@ -783,7 +786,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -844,7 +847,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the input ports
@@ -930,7 +933,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -991,7 +994,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the output ports
@@ -1078,7 +1081,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -1139,7 +1142,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the funnels
@@ -1226,7 +1229,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -1287,7 +1290,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the labels
@@ -1380,7 +1383,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -1472,7 +1475,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the remote process groups
@@ -1571,7 +1574,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -1634,7 +1637,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // all of the relationships for the specified source processor
@@ -1803,10 +1806,10 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                 final Authorizable template = lookup.getTemplate(instantiateTemplateRequestEntity.getTemplateId());
-                template.authorize(authorizer, RequestAction.READ);
+                template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -1837,7 +1840,7 @@ public class ProcessGroupResource extends ApplicationResource {
 
     private void authorizeSnippetUsage(final AuthorizableLookup lookup, final String groupId, final String snippetId) {
         // ensure write access to the target process group
-        lookup.getProcessGroup(groupId).authorize(authorizer, RequestAction.WRITE);
+        lookup.getProcessGroup(groupId).authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
         // ensure read permission to every component in the snippet
         final Snippet snippet = lookup.getSnippet(snippetId);
@@ -1885,7 +1888,7 @@ public class ProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processGroup = lookup.getProcessGroup(groupId);
-            processGroup.authorize(authorizer, RequestAction.READ);
+            processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the templates
@@ -2077,7 +2080,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -2187,7 +2190,7 @@ public class ProcessGroupResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processGroup = lookup.getProcessGroup(groupId);
-                processGroup.authorize(authorizer, RequestAction.WRITE);
+                processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
index 0847fe0..a6169aa 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.ui.extension.UiExtension;
 import org.apache.nifi.ui.extension.UiExtensionMapping;
 import org.apache.nifi.web.NiFiServiceFacade;
@@ -191,7 +192,7 @@ public class ProcessorResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processor = lookup.getProcessor(id);
-            processor.authorize(authorizer, RequestAction.READ);
+            processor.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the specified processor
@@ -262,7 +263,7 @@ public class ProcessorResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processor = lookup.getProcessor(id);
-            processor.authorize(authorizer, RequestAction.READ);
+            processor.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the property descriptor
@@ -318,7 +319,7 @@ public class ProcessorResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable processor = lookup.getProcessor(id);
-            processor.authorize(authorizer, RequestAction.WRITE);
+            processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the component state
@@ -378,7 +379,7 @@ public class ProcessorResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processor = lookup.getProcessor(id);
-                processor.authorize(authorizer, RequestAction.WRITE);
+                processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (isValidationPhase) {
@@ -464,7 +465,7 @@ public class ProcessorResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getProcessor(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateProcessor(requestProcessorDTO),
             () -> {
@@ -536,7 +537,7 @@ public class ProcessorResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable processor = lookup.getProcessor(id);
-                processor.authorize(authorizer, RequestAction.WRITE);
+                processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteProcessor(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
index cfeaff7..f4501f5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
@@ -780,14 +780,14 @@ public class ProvenanceResource extends ApplicationResource {
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
-            if (lineageDto.getClusterNodeId() == null) {
+            if (requestDto.getClusterNodeId() == null) {
                 throw new IllegalArgumentException("The cluster node identifier must be specified.");
             }
 
             // change content type to JSON for serializing entity
             final Map<String, String> headersToOverride = new HashMap<>();
             headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
-            return replicate(HttpMethod.POST, lineageEntity, lineageDto.getClusterNodeId(), headersToOverride);
+            return replicate(HttpMethod.POST, lineageEntity, requestDto.getClusterNodeId(), headersToOverride);
         }
 
         // handle expects request (usually from the cluster manager)
@@ -798,7 +798,7 @@ public class ProvenanceResource extends ApplicationResource {
 
         // get the provenance event
         final LineageDTO dto = serviceFacade.submitLineage(lineageDto);
-        dto.setClusterNodeId(lineageDto.getClusterNodeId());
+        dto.getRequest().setClusterNodeId(requestDto.getClusterNodeId());
         populateRemainingLineageContent(dto);
 
         // create a response entity
@@ -858,7 +858,7 @@ public class ProvenanceResource extends ApplicationResource {
 
         // get the lineage
         final LineageDTO dto = serviceFacade.getLineage(id);
-        dto.setClusterNodeId(clusterNodeId);
+        dto.getRequest().setClusterNodeId(clusterNodeId);
         populateRemainingLineageContent(dto);
 
         // create the response entity

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
index 9739c8c..e6669d9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
@@ -169,7 +170,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id);
-            remoteProcessGroup.authorize(authorizer, RequestAction.READ);
+            remoteProcessGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the remote process group
@@ -245,7 +246,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id);
-                remoteProcessGroup.authorize(authorizer, RequestAction.WRITE);
+                remoteProcessGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteRemoteProcessGroup(id),
             () -> {
@@ -323,7 +324,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable remoteProcessGroupInputPort = lookup.getRemoteProcessGroupInputPort(id, portId);
-                remoteProcessGroupInputPort.authorize(authorizer, RequestAction.WRITE);
+                remoteProcessGroupInputPort.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, requestRemoteProcessGroupPort),
             () -> {
@@ -412,7 +413,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable remoteProcessGroupOutputPort = lookup.getRemoteProcessGroupOutputPort(id, portId);
-                remoteProcessGroupOutputPort.authorize(authorizer, RequestAction.WRITE);
+                remoteProcessGroupOutputPort.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateRemoteProcessGroupOutputPort(id, requestRemoteProcessGroupPort),
             () -> {
@@ -492,7 +493,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getRemoteProcessGroup(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateRemoteProcessGroup(requestRemoteProcessGroup),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
index 54e63b3..0bf2c19 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.ui.extension.UiExtension;
 import org.apache.nifi.ui.extension.UiExtensionMapping;
 import org.apache.nifi.web.NiFiServiceFacade;
@@ -180,7 +181,7 @@ public class ReportingTaskResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable reportingTask = lookup.getReportingTask(id);
-            reportingTask.authorize(authorizer, RequestAction.READ);
+            reportingTask.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the reporting task
@@ -244,7 +245,7 @@ public class ReportingTaskResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable reportingTask = lookup.getReportingTask(id);
-            reportingTask.authorize(authorizer, RequestAction.READ);
+            reportingTask.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the property descriptor
@@ -299,7 +300,7 @@ public class ReportingTaskResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable reportingTask = lookup.getReportingTask(id);
-            reportingTask.authorize(authorizer, RequestAction.WRITE);
+            reportingTask.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
         });
 
         // get the component state
@@ -358,7 +359,7 @@ public class ReportingTaskResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable processor = lookup.getReportingTask(id);
-                processor.authorize(authorizer, RequestAction.WRITE);
+                processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (isValidationPhase) {
@@ -443,7 +444,7 @@ public class ReportingTaskResource extends ApplicationResource {
             revision,
             lookup -> {
                 Authorizable authorizable = lookup.getReportingTask(id);
-                authorizable.authorize(authorizer, RequestAction.WRITE);
+                authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyUpdateReportingTask(requestReportingTaskDTO),
             () -> {
@@ -518,7 +519,7 @@ public class ReportingTaskResource extends ApplicationResource {
             revision,
             lookup -> {
                 final Authorizable reportingTask = lookup.getReportingTask(id);
-                reportingTask.authorize(authorizer, RequestAction.WRITE);
+                reportingTask.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             },
             () -> serviceFacade.verifyDeleteReportingTask(id),
             () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SnippetResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SnippetResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SnippetResource.java
index 2f9b32b..9669017 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SnippetResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SnippetResource.java
@@ -35,6 +35,7 @@ import javax.ws.rs.core.Response;
 
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.controller.Snippet;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
@@ -228,7 +229,7 @@ public class SnippetResource extends ApplicationResource {
             lookup -> {
                 // ensure write access to the target process group
                 if (requestSnippetDTO.getParentGroupId() != null) {
-                    lookup.getProcessGroup(requestSnippetDTO.getParentGroupId()).authorize(authorizer, RequestAction.WRITE);
+                    lookup.getProcessGroup(requestSnippetDTO.getParentGroupId()).authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 }
 
                 // ensure read permission to every component in the snippet

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
index 9a3f87b..6994815 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
@@ -34,6 +34,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.api.dto.TemplateDTO;
 import org.apache.nifi.web.api.entity.TemplateEntity;
@@ -123,7 +124,7 @@ public class TemplateResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable template = lookup.getTemplate(id);
-            template.authorize(authorizer, RequestAction.READ);
+            template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the template
@@ -190,7 +191,7 @@ public class TemplateResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable template = lookup.getTemplate(id);
-                template.authorize(authorizer, RequestAction.WRITE);
+                template.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
             return generateContinueResponse().build();
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
index 5903b2d..4c6dcd3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TenantsResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.coordination.ClusterCoordinator;
 import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
 import org.apache.nifi.util.NiFiProperties;
@@ -182,7 +183,7 @@ public class TenantsResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable users = lookup.getTenantAuthorizable();
-                users.authorize(authorizer, RequestAction.WRITE);
+                users.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -247,7 +248,7 @@ public class TenantsResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable users = lookup.getTenantAuthorizable();
-            users.authorize(authorizer, RequestAction.READ);
+            users.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the user
@@ -294,7 +295,7 @@ public class TenantsResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable users = lookup.getTenantAuthorizable();
-            users.authorize(authorizer, RequestAction.READ);
+            users.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the users
@@ -375,7 +376,7 @@ public class TenantsResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     final Authorizable users = lookup.getTenantAuthorizable();
-                    users.authorize(authorizer, RequestAction.WRITE);
+                users.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 },
                 null,
                 () -> {
@@ -450,7 +451,7 @@ public class TenantsResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     final Authorizable users = lookup.getTenantAuthorizable();
-                    users.authorize(authorizer, RequestAction.READ);
+                users.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
                 },
                 null,
                 () -> {
@@ -567,7 +568,7 @@ public class TenantsResource extends ApplicationResource {
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 final Authorizable userGroups = lookup.getTenantAuthorizable();
-                userGroups.authorize(authorizer, RequestAction.WRITE);
+                userGroups.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
             });
         }
         if (validationPhase) {
@@ -632,7 +633,7 @@ public class TenantsResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable userGroups = lookup.getTenantAuthorizable();
-            userGroups.authorize(authorizer, RequestAction.READ);
+            userGroups.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get the user group
@@ -679,7 +680,7 @@ public class TenantsResource extends ApplicationResource {
         // authorize access
         serviceFacade.authorizeAccess(lookup -> {
             final Authorizable userGroups = lookup.getTenantAuthorizable();
-            userGroups.authorize(authorizer, RequestAction.READ);
+            userGroups.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         });
 
         // get all the user groups
@@ -760,7 +761,7 @@ public class TenantsResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     final Authorizable userGroups = lookup.getTenantAuthorizable();
-                    userGroups.authorize(authorizer, RequestAction.WRITE);
+                userGroups.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
                 },
                 null,
                 () -> {
@@ -835,7 +836,7 @@ public class TenantsResource extends ApplicationResource {
                 revision,
                 lookup -> {
                     final Authorizable userGroups = lookup.getTenantAuthorizable();
-                    userGroups.authorize(authorizer, RequestAction.READ);
+                userGroups.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
                 },
                 null,
                 () -> {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
index 93d1bab..b3244b6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
@@ -49,17 +49,13 @@ public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDenied
             status = Status.FORBIDDEN;
         }
 
-        if (user != null) {
-            logger.info(String.format("%s does not have permission to access the requested resource. Returning %s response.", user.getIdentity(), status));
-        } else {
-            logger.info(String.format("User does not have permission to access the requested resource. Returning %s response.", status));
-        }
+        logger.info(String.format("%s does not have permission to access the requested resource. Returning %s response.", user.getIdentity(), status));
 
         if (logger.isDebugEnabled()) {
             logger.debug(StringUtils.EMPTY, exception);
         }
 
-        return Response.status(status).entity("Unable to perform the desired action. Contact the system administrator.").type("text/plain").build();
+        return Response.status(status).entity("Unable to perform the desired action due to insufficient permissions. Contact the system administrator.").type("text/plain").build();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 8889292..3689680 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -41,6 +41,7 @@ import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.Resource;
 import org.apache.nifi.authorization.User;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
 import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
 import org.apache.nifi.cluster.event.NodeEvent;
@@ -1579,8 +1580,8 @@ public final class DtoFactory {
      */
     public AccessPolicyDTO createAccessPolicyDto(final Authorizable authorizable) {
         final AccessPolicyDTO dto = new AccessPolicyDTO();
-        dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ));
-        dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE));
+        dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()));
+        dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()));
         return dto;
     }
 
@@ -2461,7 +2462,7 @@ public final class DtoFactory {
                 final List<AllowableValueDTO> allowableValues = new ArrayList<>();
                 for (final String serviceIdentifier : controllerServiceProvider.getControllerServiceIdentifiers(serviceDefinition, groupId)) {
                     final ControllerServiceNode service = controllerServiceProvider.getControllerServiceNode(serviceIdentifier);
-                    final String displayName = service.isAuthorized(authorizer, RequestAction.READ) ? service.getName() : serviceIdentifier;
+                    final String displayName = service.isAuthorized(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()) ? service.getName() : serviceIdentifier;
 
                     final AllowableValueDTO allowableValue = new AllowableValueDTO();
                     allowableValue.setDisplayName(displayName);


[2/4] nifi git commit: NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index 5d41c2c..b72d72c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -19,10 +19,6 @@ package org.apache.nifi.web.controller;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-import org.apache.nifi.authorization.AuthorizationResult;
-import org.apache.nifi.authorization.AuthorizationResult.Result;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.Resource;
@@ -31,6 +27,7 @@ import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.cluster.coordination.ClusterCoordinator;
 import org.apache.nifi.cluster.coordination.node.NodeConnectionState;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
@@ -116,7 +113,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.io.InputStream;
 import java.text.Collator;
@@ -803,7 +799,7 @@ public class ControllerFacade implements Authorizable {
         // add each processor
         for (final ProcessorNode processor : root.findAllProcessors()) {
             resources.add(ResourceFactory.getComponentResource(ResourceType.Processor, processor.getIdentifier(), processor.getName()));
-            resources.add(ResourceFactory.getComponentProvenanceResource(ResourceType.Processor, processor.getIdentifier(), processor.getName()));
+            resources.add(ResourceFactory.getProvenanceEventResource(processor.getResource()));
         }
 
         // add each connection
@@ -820,25 +816,25 @@ public class ControllerFacade implements Authorizable {
         // add each process group
         for (final ProcessGroup processGroup : root.findAllProcessGroups()) {
             resources.add(ResourceFactory.getComponentResource(ResourceType.ProcessGroup, processGroup.getIdentifier(), processGroup.getName()));
-            resources.add(ResourceFactory.getComponentProvenanceResource(ResourceType.ProcessGroup, processGroup.getIdentifier(), processGroup.getName()));
+            resources.add(ResourceFactory.getProvenanceEventResource(processGroup.getResource()));
         }
 
         // add each remote process group
         for (final RemoteProcessGroup remoteProcessGroup : root.findAllRemoteProcessGroups()) {
             resources.add(ResourceFactory.getComponentResource(ResourceType.RemoteProcessGroup, remoteProcessGroup.getIdentifier(), remoteProcessGroup.getName()));
-            resources.add(ResourceFactory.getComponentProvenanceResource(ResourceType.RemoteProcessGroup, remoteProcessGroup.getIdentifier(), remoteProcessGroup.getName()));
+            resources.add(ResourceFactory.getProvenanceEventResource(remoteProcessGroup.getResource()));
         }
 
         // add each input port
         for (final Port inputPort : root.findAllInputPorts()) {
             resources.add(ResourceFactory.getComponentResource(ResourceType.InputPort, inputPort.getIdentifier(), inputPort.getName()));
-            resources.add(ResourceFactory.getComponentProvenanceResource(ResourceType.InputPort, inputPort.getIdentifier(), inputPort.getName()));
+            resources.add(ResourceFactory.getProvenanceEventResource(inputPort.getResource()));
         }
 
         // add each output port
         for (final Port outputPort : root.findAllOutputPorts()) {
             resources.add(ResourceFactory.getComponentResource(ResourceType.OutputPort, outputPort.getIdentifier(), outputPort.getName()));
-            resources.add(ResourceFactory.getComponentProvenanceResource(ResourceType.OutputPort, outputPort.getIdentifier(), outputPort.getName()));
+            resources.add(ResourceFactory.getProvenanceEventResource(outputPort.getResource()));
         }
 
         // add each controller service
@@ -943,7 +939,7 @@ public class ControllerFacade implements Authorizable {
 
         // submit the query to the provenance repository
         final ProvenanceEventRepository provenanceRepository = flowController.getProvenanceRepository();
-        final QuerySubmission querySubmission = provenanceRepository.submitQuery(query);
+        final QuerySubmission querySubmission = provenanceRepository.submitQuery(query, NiFiUserUtils.getNiFiUser());
 
         // return the query with the results populated at this point
         return getProvenanceQuery(querySubmission.getQueryIdentifier());
@@ -959,7 +955,7 @@ public class ControllerFacade implements Authorizable {
         try {
             // get the query to the provenance repository
             final ProvenanceEventRepository provenanceRepository = flowController.getProvenanceRepository();
-            final QuerySubmission querySubmission = provenanceRepository.retrieveQuerySubmission(provenanceId);
+            final QuerySubmission querySubmission = provenanceRepository.retrieveQuerySubmission(provenanceId, NiFiUserUtils.getNiFiUser());
 
             // ensure the query results could be found
             if (querySubmission == null) {
@@ -1056,13 +1052,13 @@ public class ControllerFacade implements Authorizable {
         // submit the event
         if (LineageRequestType.FLOWFILE.equals(requestDto.getLineageRequestType())) {
             // submit uuid
-            result = provenanceRepository.submitLineageComputation(requestDto.getUuid());
+            result = provenanceRepository.submitLineageComputation(requestDto.getUuid(), NiFiUserUtils.getNiFiUser());
         } else {
             // submit event... (parents or children)
             if (LineageRequestType.PARENTS.equals(requestDto.getLineageRequestType())) {
-                result = provenanceRepository.submitExpandParents(requestDto.getEventId());
+                result = provenanceRepository.submitExpandParents(requestDto.getEventId(), NiFiUserUtils.getNiFiUser());
             } else {
-                result = provenanceRepository.submitExpandChildren(requestDto.getEventId());
+                result = provenanceRepository.submitExpandChildren(requestDto.getEventId(), NiFiUserUtils.getNiFiUser());
             }
         }
 
@@ -1078,7 +1074,7 @@ public class ControllerFacade implements Authorizable {
     public LineageDTO getLineage(final String lineageId) {
         // get the query to the provenance repository
         final ProvenanceEventRepository provenanceRepository = flowController.getProvenanceRepository();
-        final ComputeLineageSubmission computeLineageSubmission = provenanceRepository.retrieveLineageSubmission(lineageId);
+        final ComputeLineageSubmission computeLineageSubmission = provenanceRepository.retrieveLineageSubmission(lineageId, NiFiUserUtils.getNiFiUser());
 
         // ensure the submission was found
         if (computeLineageSubmission == null) {
@@ -1096,7 +1092,7 @@ public class ControllerFacade implements Authorizable {
     public void deleteProvenanceQuery(final String provenanceId) {
         // get the query to the provenance repository
         final ProvenanceEventRepository provenanceRepository = flowController.getProvenanceRepository();
-        final QuerySubmission querySubmission = provenanceRepository.retrieveQuerySubmission(provenanceId);
+        final QuerySubmission querySubmission = provenanceRepository.retrieveQuerySubmission(provenanceId, NiFiUserUtils.getNiFiUser());
         if (querySubmission != null) {
             querySubmission.cancel();
         }
@@ -1110,7 +1106,7 @@ public class ControllerFacade implements Authorizable {
     public void deleteLineage(final String lineageId) {
         // get the query to the provenance repository
         final ProvenanceEventRepository provenanceRepository = flowController.getProvenanceRepository();
-        final ComputeLineageSubmission computeLineageSubmission = provenanceRepository.retrieveLineageSubmission(lineageId);
+        final ComputeLineageSubmission computeLineageSubmission = provenanceRepository.retrieveLineageSubmission(lineageId, NiFiUserUtils.getNiFiUser());
         if (computeLineageSubmission != null) {
             computeLineageSubmission.cancel();
         }
@@ -1129,7 +1125,7 @@ public class ControllerFacade implements Authorizable {
             final NiFiUser user = NiFiUserUtils.getNiFiUser();
 
             // get the event in order to get the filename
-            final ProvenanceEventRecord event = flowController.getProvenanceRepository().getEvent(eventId);
+            final ProvenanceEventRecord event = flowController.getProvenanceRepository().getEvent(eventId, NiFiUserUtils.getNiFiUser());
             if (event == null) {
                 throw new ResourceNotFoundException("Unable to find the specified event.");
             }
@@ -1145,54 +1141,18 @@ public class ControllerFacade implements Authorizable {
             // calculate the dn chain
             final List<String> dnChain = ProxiedEntitiesUtils.buildProxiedEntitiesChain(user);
             dnChain.forEach(identity -> {
-                final String rootGroupId = flowController.getRootGroupId();
-                final ProcessGroup rootGroup = flowController.getGroup(rootGroupId);
-
-                final Resource eventResource;
-                if (rootGroupId.equals(event.getComponentId())) {
-                    eventResource = ResourceFactory.getComponentProvenanceResource(ResourceType.ProcessGroup, rootGroup.getIdentifier(), rootGroup.getName());
-                } else {
-                    final Connectable connectable = rootGroup.findConnectable(event.getComponentId());
-
-                    if (connectable == null) {
-                        throw new AccessDeniedException("The component that generated this event is no longer part of the data flow. Unable to determine access policy.");
-                    }
-
-                    switch (connectable.getConnectableType()) {
-                        case PROCESSOR:
-                            eventResource = ResourceFactory.getComponentProvenanceResource(ResourceType.Processor, connectable.getIdentifier(), connectable.getName());
-                            break;
-                        case INPUT_PORT:
-                        case REMOTE_INPUT_PORT:
-                            eventResource = ResourceFactory.getComponentProvenanceResource(ResourceType.InputPort, connectable.getIdentifier(), connectable.getName());
-                            break;
-                        case OUTPUT_PORT:
-                        case REMOTE_OUTPUT_PORT:
-                            eventResource = ResourceFactory.getComponentProvenanceResource(ResourceType.OutputPort, connectable.getIdentifier(), connectable.getName());
-                            break;
-                        case FUNNEL:
-                            eventResource = ResourceFactory.getComponentProvenanceResource(ResourceType.Funnel, connectable.getIdentifier(), connectable.getName());
-                            break;
-                        default:
-                            throw new WebApplicationException(Response.serverError().entity("An unexpected type of component generated this event.").build());
+                final Authorizable eventAuthorizable = flowController.createProvenanceAuthorizable(event.getComponentId());
+                final NiFiUser chainUser = new StandardNiFiUser(identity) {
+                    private static final long serialVersionUID = 7589311627013017356L;
+
+                    @Override
+                    public boolean isAnonymous() {
+                        // allow current user to drive anonymous flag as anonymous users are never chained... supports single user case
+                        return user.isAnonymous();
                     }
-                }
+                };
 
-                // build the request
-                final AuthorizationRequest request = new AuthorizationRequest.Builder()
-                        .identity(identity)
-                        .anonymous(user.isAnonymous()) // allow current user to drive anonymous flag as anonymous users are never chained... supports single user case
-                        .accessAttempt(false)
-                        .action(RequestAction.READ)
-                        .resource(eventResource)
-                        .eventAttributes(attributes)
-                        .build();
-
-                // perform the authorization
-                final AuthorizationResult result = authorizer.authorize(request);
-                if (!Result.Approved.equals(result.getResult())) {
-                    throw new AccessDeniedException(result.getExplanation());
-                }
+                eventAuthorizable.authorize(authorizer, RequestAction.READ, chainUser);
             });
 
             // get the filename and fall back to the identifier (should never happen)
@@ -1229,13 +1189,13 @@ public class ControllerFacade implements Authorizable {
             }
 
             // lookup the original event
-            final ProvenanceEventRecord originalEvent = flowController.getProvenanceRepository().getEvent(eventId);
+            final ProvenanceEventRecord originalEvent = flowController.getProvenanceRepository().getEvent(eventId, NiFiUserUtils.getNiFiUser());
             if (originalEvent == null) {
                 throw new ResourceNotFoundException("Unable to find the specified event.");
             }
 
             // replay the flow file
-            final ProvenanceEventRecord event = flowController.replayFlowFile(originalEvent, user.getIdentity());
+            final ProvenanceEventRecord event = flowController.replayFlowFile(originalEvent, user);
 
             // convert the event record
             return createProvenanceEventDto(event);
@@ -1252,7 +1212,7 @@ public class ControllerFacade implements Authorizable {
      */
     public ProvenanceEventDTO getProvenanceEvent(final Long eventId) {
         try {
-            final ProvenanceEventRecord event = flowController.getProvenanceRepository().getEvent(eventId);
+            final ProvenanceEventRecord event = flowController.getProvenanceRepository().getEvent(eventId, NiFiUserUtils.getNiFiUser());
             if (event == null) {
                 throw new ResourceNotFoundException("Unable to find the specified event.");
             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
index e16dd05..1a2669b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
@@ -298,7 +298,7 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
         }
 
         // ensure the user has write access to the source component
-        source.authorize(authorizer, RequestAction.WRITE);
+        source.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
         // find the destination
         final Connectable destination;
@@ -324,7 +324,7 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
         }
 
         // ensure the user has write access to the source component
-        destination.authorize(authorizer, RequestAction.WRITE);
+        destination.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
         // determine the relationships
         final Set<String> relationships = new HashSet<>();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/StandardNiFiServiceFacadeSpec.groovy
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/StandardNiFiServiceFacadeSpec.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/StandardNiFiServiceFacadeSpec.groovy
index 7b5f594..87dbf86 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/StandardNiFiServiceFacadeSpec.groovy
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/StandardNiFiServiceFacadeSpec.groovy
@@ -20,6 +20,7 @@ import org.apache.nifi.authorization.*
 import org.apache.nifi.authorization.resource.Authorizable
 import org.apache.nifi.authorization.resource.ResourceFactory
 import org.apache.nifi.authorization.user.NiFiUser
+import org.apache.nifi.authorization.user.StandardNiFiUser
 import org.apache.nifi.authorization.user.NiFiUserDetails
 import org.apache.nifi.controller.service.ControllerServiceProvider
 import org.apache.nifi.web.api.dto.*
@@ -39,7 +40,7 @@ import spock.lang.Unroll
 class StandardNiFiServiceFacadeSpec extends Specification {
 
     def setup() {
-        final NiFiUser user = new NiFiUser("nifi-user");
+        final NiFiUser user = new StandardNiFiUser("nifi-user");
         final NiFiAuthenticationToken auth = new NiFiAuthenticationToken(new NiFiUserDetails(user));
         SecurityContextHolder.getContext().setAuthentication(auth);
     }
@@ -867,17 +868,17 @@ class StandardNiFiServiceFacadeSpec extends Specification {
         }
 
         @Override
-        boolean isAuthorized(Authorizer authorzr, RequestAction action) {
+        boolean isAuthorized(Authorizer authorzr, RequestAction action, NiFiUser user) {
             return isAuthorized
         }
 
         @Override
-        AuthorizationResult checkAuthorization(Authorizer authorzr, RequestAction action) {
+        AuthorizationResult checkAuthorization(Authorizer authorzr, RequestAction action, NiFiUser user) {
             return authorizationResult
         }
 
         @Override
-        void authorize(Authorizer authorzr, RequestAction action) throws AccessDeniedException {
+        void authorize(Authorizer authorzr, RequestAction action, NiFiUser user) throws AccessDeniedException {
             if (!isAuthorized) {
                 throw new AccessDeniedException("test exception, access denied")
             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/test/java/org/apache/nifi/web/revision/TestNaiveRevisionManager.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/test/java/org/apache/nifi/web/revision/TestNaiveRevisionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/test/java/org/apache/nifi/web/revision/TestNaiveRevisionManager.java
index e3148d3..a4e17e8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/test/java/org/apache/nifi/web/revision/TestNaiveRevisionManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/test/java/org/apache/nifi/web/revision/TestNaiveRevisionManager.java
@@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.web.FlowModification;
 import org.apache.nifi.web.InvalidRevisionException;
 import org.apache.nifi.web.Revision;
@@ -49,7 +50,7 @@ import org.junit.Test;
 public class TestNaiveRevisionManager {
     private static final String CLIENT_1 = "client-1";
     private static final String COMPONENT_1 = "component-1";
-    private static final NiFiUser USER_1 = new NiFiUser("user-1");
+    private static final NiFiUser USER_1 = new StandardNiFiUser("user-1");
 
     private RevisionUpdate<Object> components(final Revision revision) {
         return new StandardRevisionUpdate<Object>(null, new FlowModification(revision, null));
@@ -302,7 +303,7 @@ public class TestNaiveRevisionManager {
         final RevisionClaim firstClaim = revisionManager.requestClaim(firstRevision, USER_1);
         assertNotNull(firstClaim);
 
-        final NiFiUser user2 = new NiFiUser("user-2");
+        final NiFiUser user2 = new StandardNiFiUser("user-2");
         try {
             revisionManager.updateRevision(firstClaim, user2, () -> null);
             Assert.fail("Expected updateRevision to fail with a different user but it succeeded");
@@ -318,7 +319,7 @@ public class TestNaiveRevisionManager {
         final RevisionClaim firstClaim = revisionManager.requestClaim(firstRevision, USER_1);
         assertNotNull(firstClaim);
 
-        final NiFiUser user2 = new NiFiUser("user-2");
+        final NiFiUser user2 = new StandardNiFiUser("user-2");
         try {
             revisionManager.deleteRevision(firstClaim, user2, () -> null);
             Assert.fail("Expected deleteRevision to fail with a different user but it succeeded");

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/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 b1a9a66..da9c52e 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,14 +16,14 @@
  */
 package org.apache.nifi.web.security.anonymous;
 
-import org.apache.nifi.authorization.user.NiFiUser;
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
 
-import javax.servlet.http.HttpServletRequest;
-
 public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
     private static final String ANONYMOUS_KEY = "anonymousNifiKey";
@@ -34,7 +34,7 @@ public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
     @Override
     protected Authentication createAuthentication(HttpServletRequest request) {
-        return new NiFiAuthenticationToken(new NiFiUserDetails(NiFiUser.ANONYMOUS));
+        return new NiFiAuthenticationToken(new NiFiUserDetails(StandardNiFiUser.ANONYMOUS));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.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/JwtAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
index 7634123..f68935e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
@@ -16,15 +16,17 @@
  */
 package org.apache.nifi.web.security.jwt;
 
-import io.jsonwebtoken.JwtException;
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 
+import io.jsonwebtoken.JwtException;
+
 /**
  *
  */
@@ -42,7 +44,7 @@ public class JwtAuthenticationProvider implements AuthenticationProvider {
 
         try {
             final String jwtPrincipal = jwtService.getAuthenticationFromToken(request.getToken());
-            final NiFiUser user = new NiFiUser(jwtPrincipal);
+            final NiFiUser user = new StandardNiFiUser(jwtPrincipal);
             return new NiFiAuthenticationToken(new NiFiUserDetails(user));
         } catch (JwtException e) {
             throw new InvalidAuthenticationException(e.getMessage(), e);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.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/otp/OtpAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
index 8f2712c..b80a97e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
@@ -18,6 +18,7 @@ package org.apache.nifi.web.security.otp;
 
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationProvider;
@@ -46,7 +47,7 @@ public class OtpAuthenticationProvider implements AuthenticationProvider {
             } else {
                 otpPrincipal = otpService.getAuthenticationFromUiExtensionToken(request.getToken());
             }
-            final NiFiUser user = new NiFiUser(otpPrincipal);
+            final NiFiUser user = new StandardNiFiUser(otpPrincipal);
             return new NiFiAuthenticationToken(new NiFiUserDetails(user));
         } catch (OtpAuthenticationException e) {
             throw new InvalidAuthenticationException(e.getMessage(), e);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/NiFiAuthenticationToken.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/token/NiFiAuthenticationToken.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/NiFiAuthenticationToken.java
index f7964f5..564ac5f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/NiFiAuthenticationToken.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/token/NiFiAuthenticationToken.java
@@ -47,4 +47,9 @@ public class NiFiAuthenticationToken extends AbstractAuthenticationToken {
     public final void setAuthenticated(boolean authenticated) {
         throw new IllegalArgumentException("Cannot change the authenticated state.");
     }
+
+    @Override
+    public String toString() {
+        return nifiUserDetails.getUsername();
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.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/x509/X509AuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
index 43d6958..b72d5e1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
@@ -26,6 +26,7 @@ import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.ProxiedEntitiesUtils;
 import org.apache.nifi.web.security.UntrustedProxyException;
@@ -64,7 +65,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider {
         }
 
         if (StringUtils.isBlank(request.getProxiedEntitiesChain())) {
-            return new NiFiAuthenticationToken(new NiFiUserDetails(new NiFiUser(authenticationResponse.getIdentity(), authenticationResponse.getUsername(), null)));
+            return new NiFiAuthenticationToken(new NiFiUserDetails(new StandardNiFiUser(authenticationResponse.getIdentity(), authenticationResponse.getUsername(), null)));
         } else {
             // build the entire proxy chain if applicable - <end-user><proxy1><proxy2>
             final List<String> proxyChain = new ArrayList<>(ProxiedEntitiesUtils.tokenizeProxiedEntitiesChain(request.getProxiedEntitiesChain()));
@@ -91,7 +92,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider {
                     }
                 }
 
-                proxy = new NiFiUser(chainIter.previous(), proxy);
+                proxy = new StandardNiFiUser(chainIter.previous(), proxy);
             }
 
             return new NiFiAuthenticationToken(new NiFiUserDetails(proxy));

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js
index 7c27746..04a2204 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-lineage.js
@@ -145,9 +145,9 @@ nf.ProvenanceLineage = (function () {
      */
     var getLineage = function (lineage) {
         var url = lineage.uri;
-        if (nf.Common.isDefinedAndNotNull(lineage.clusterNodeId)) {
+        if (nf.Common.isDefinedAndNotNull(lineage.request.clusterNodeId)) {
             url += '?' + $.param({
-                    clusterNodeId: lineage.clusterNodeId
+                    clusterNodeId: lineage.request.clusterNodeId
                 });
         }
 
@@ -166,9 +166,9 @@ nf.ProvenanceLineage = (function () {
      */
     var cancelLineage = function (lineage) {
         var url = lineage.uri;
-        if (nf.Common.isDefinedAndNotNull(lineage.clusterNodeId)) {
+        if (nf.Common.isDefinedAndNotNull(lineage.request.clusterNodeId)) {
             url += '?' + $.param({
-                    clusterNodeId: lineage.clusterNodeId
+                    clusterNodeId: lineage.request.clusterNodeId
                 });
         }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js
index ca1a83e..f024866 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js
@@ -384,7 +384,7 @@ nf.ProvenanceTable = (function () {
                                 startTime = config.defaultStartTime;
                                 $('#provenance-search-start-time').val(startTime);
                             }
-                            search['startDate'] = startDate + ' ' + startTime;
+                            search['startDate'] = startDate + ' ' + startTime + ' ' + $('.timezone:first').text();
                         }
 
                         // extract the end date time
@@ -395,7 +395,7 @@ nf.ProvenanceTable = (function () {
                                 endTime = config.defaultEndTime;
                                 $('#provenance-search-end-time').val(endTime);
                             }
-                            search['endDate'] = endDate + ' ' + endTime;
+                            search['endDate'] = endDate + ' ' + endTime + ' ' + $('.timezone:first').text();
                         }
 
                         // extract the min/max file size

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js
index e1891a2..a04aad7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js
@@ -29,7 +29,7 @@ nf.Provenance = (function () {
      */
     var config = {
         urls: {
-            cluster: '../nifi-api/controller/cluster',
+            flowConfig: '../nifi-api/flow/config',
             banners: '../nifi-api/flow/banners',
             about: '../nifi-api/flow/about',
             authorities: '../nifi-api/flow/authorities'
@@ -45,23 +45,12 @@ nf.Provenance = (function () {
      * Determines if this NiFi is clustered.
      */
     var detectedCluster = function () {
-        return $.Deferred(function (deferred) {
-            $.ajax({
-                type: 'HEAD',
-                url: config.urls.cluster
-            }).done(function () {
-                isClustered = true;
-                deferred.resolve();
-            }).fail(function (xhr, status, error) {
-                if (xhr.status === 404) {
-                    isClustered = false;
-                    deferred.resolve();
-                } else {
-                    nf.Common.handleAjaxError(xhr, status, error);
-                    deferred.reject();
-                }
-            });
-        }).promise();
+        return $.ajax({
+                type: 'GET',
+                url: config.urls.flowConfig
+            }).done(function (response) {
+                isClustered = response.flowConfiguration.clustered;
+            }).fail(nf.Common.handleAjaxError);
     };
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js
index b8c1a58..8476621 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js
@@ -51,7 +51,7 @@ nf.Summary = (function () {
         urls: {
             banners: '../nifi-api/flow/banners',
             about: '../nifi-api/flow/about',
-            cluster: '../nifi-api/controller/cluster'
+            flowConfig: '../nifi-api/flow/config'
         }
     };
 
@@ -61,26 +61,15 @@ nf.Summary = (function () {
     var initializeSummaryTable = function () {
         return $.Deferred(function (deferred) {
             $.ajax({
-                type: 'HEAD',
-                url: config.urls.cluster
-            }).done(function () {
-                nf.SummaryTable.init(true).done(function () {
+                type: 'GET',
+                url: config.urls.flowConfig
+            }).done(function (response) {
+                nf.SummaryTable.init(response.flowConfiguration.clustered).done(function () {
                     deferred.resolve();
                 }).fail(function () {
                     deferred.reject();
                 });
-            }).fail(function (xhr, status, error) {
-                if (xhr.status === 404) {
-                    nf.SummaryTable.init(false).done(function () {
-                        deferred.resolve();
-                    }).fail(function () {
-                        deferred.reject();
-                    });
-                } else {
-                    nf.Common.handleAjaxError(xhr, status, error);
-                    deferred.reject();
-                }
-            });
+            }).fail(nf.Common.handleAjaxError);
         }).promise();
     };
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/PersistentProvenanceRepository.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/PersistentProvenanceRepository.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/PersistentProvenanceRepository.java
index b8d6f35..adb335c 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/PersistentProvenanceRepository.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/PersistentProvenanceRepository.java
@@ -59,6 +59,7 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.DirectoryReader;
@@ -68,6 +69,13 @@ import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.TopDocs;
 import org.apache.lucene.store.FSDirectory;
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.processor.DataUnit;
 import org.apache.nifi.provenance.expiration.ExpirationAction;
@@ -99,6 +107,7 @@ import org.apache.nifi.util.RingBuffer;
 import org.apache.nifi.util.RingBuffer.ForEachEvaluator;
 import org.apache.nifi.util.StopWatch;
 import org.apache.nifi.util.Tuple;
+import org.apache.nifi.web.ResourceNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -163,7 +172,9 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     // we keep the last 1000 records on hand so that when the UI is opened and it asks for the last 1000 records we don't need to
     // read them. Since this is a very cheap operation to keep them, it's worth the tiny expense for the improved user experience.
     private final RingBuffer<ProvenanceEventRecord> latestRecords = new RingBuffer<>(1000);
-    private EventReporter eventReporter;
+    private EventReporter eventReporter; // effectively final
+    private Authorizer authorizer;  // effectively final
+    private ProvenanceAuthorizableFactory resourceFactory;  // effectively final
 
     public PersistentProvenanceRepository() throws IOException {
         this(createRepositoryConfiguration(), 10000);
@@ -207,7 +218,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public void initialize(final EventReporter eventReporter) throws IOException {
+    public void initialize(final EventReporter eventReporter, final Authorizer authorizer, final ProvenanceAuthorizableFactory resourceFactory) throws IOException {
         writeLock.lock();
         try {
             if (initialized.getAndSet(true)) {
@@ -215,6 +226,8 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
             }
 
             this.eventReporter = eventReporter;
+            this.authorizer = authorizer;
+            this.resourceFactory = resourceFactory;
 
             recover();
 
@@ -391,8 +404,46 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         persistRecord(events);
     }
 
+    public boolean isAuthorized(final ProvenanceEventRecord event, final NiFiUser user) {
+        if (authorizer == null || user == null) {
+            return true;
+        }
+
+        final Authorizable eventAuthorizable;
+        try {
+            eventAuthorizable = resourceFactory.createProvenanceAuthorizable(event.getComponentId());
+        } catch (final ResourceNotFoundException rnfe) {
+            return false;
+        }
+
+        final AuthorizationResult result = eventAuthorizable.checkAuthorization(authorizer, RequestAction.READ, user);
+        return Result.Approved.equals(result.getResult());
+    }
+
+    protected void authorize(final ProvenanceEventRecord event, final NiFiUser user) {
+        if (authorizer == null) {
+            return;
+        }
+
+        final Authorizable eventAuthorizable = resourceFactory.createProvenanceAuthorizable(event.getComponentId());
+        eventAuthorizable.authorize(authorizer, RequestAction.READ, user);
+    }
+
+    private List<ProvenanceEventRecord> filterUnauthorizedEvents(final List<ProvenanceEventRecord> events, final NiFiUser user) {
+        return events.stream().filter(event -> isAuthorized(event, user)).collect(Collectors.<ProvenanceEventRecord> toList());
+    }
+
+    private Set<ProvenanceEventRecord> replaceUnauthorizedWithPlaceholders(final Set<ProvenanceEventRecord> events, final NiFiUser user) {
+        return events.stream().map(event -> isAuthorized(event, user) ? event : new PlaceholderProvenanceEvent(event)).collect(Collectors.toSet());
+    }
+
     @Override
     public List<ProvenanceEventRecord> getEvents(final long firstRecordId, final int maxRecords) throws IOException {
+        return getEvents(firstRecordId, maxRecords, null);
+    }
+
+    @Override
+    public List<ProvenanceEventRecord> getEvents(final long firstRecordId, final int maxRecords, final NiFiUser user) throws IOException {
         final List<ProvenanceEventRecord> records = new ArrayList<>(maxRecords);
 
         final List<Path> paths = getPathsForId(firstRecordId);
@@ -417,7 +468,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
 
                 StandardProvenanceEventRecord record;
                 while (records.size() < maxRecords && (record = reader.nextRecord()) != null) {
-                    if (record.getEventId() >= firstRecordId) {
+                    if (record.getEventId() >= firstRecordId && isAuthorized(record, user)) {
                         records.add(record);
                     }
                 }
@@ -1807,8 +1858,8 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         return new ArrayList<>(configuration.getSearchableAttributes());
     }
 
-    QueryResult queryEvents(final Query query) throws IOException {
-        final QuerySubmission submission = submitQuery(query);
+    QueryResult queryEvents(final Query query, final NiFiUser user) throws IOException {
+        final QuerySubmission submission = submitQuery(query, user);
         final QueryResult result = submission.getResult();
         while (!result.isFinished()) {
             try {
@@ -1826,8 +1877,10 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public QuerySubmission submitQuery(final Query query) {
+    public QuerySubmission submitQuery(final Query query, final NiFiUser user) {
+        final String userId = user.getIdentity();
         final int numQueries = querySubmissionMap.size();
+
         if (numQueries > MAX_UNDELETED_QUERY_RESULTS) {
             throw new IllegalStateException("Cannot process query because there are currently " + numQueries + " queries whose results have not "
                     + "been deleted due to poorly behaving clients not issuing DELETE requests. Please try again later.");
@@ -1838,10 +1891,10 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         }
 
         if (query.getSearchTerms().isEmpty() && query.getStartDate() == null && query.getEndDate() == null) {
-            final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1);
+            final AsyncQuerySubmission result = new AsyncQuerySubmission(query, 1, userId);
 
             if (latestRecords.getSize() >= query.getMaxResults()) {
-                final List<ProvenanceEventRecord> latestList = latestRecords.asList();
+                final List<ProvenanceEventRecord> latestList = filterUnauthorizedEvents(latestRecords.asList(), user);
                 final List<ProvenanceEventRecord> trimmed;
                 if (latestList.size() > query.getMaxResults()) {
                     trimmed = latestList.subList(latestList.size() - query.getMaxResults(), latestList.size());
@@ -1863,7 +1916,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
 
                 result.getResult().update(trimmed, totalNumDocs);
             } else {
-                queryExecService.submit(new GetMostRecentRunnable(query, result));
+                queryExecService.submit(new GetMostRecentRunnable(query, result, user));
             }
 
             querySubmissionMap.put(query.getIdentifier(), result);
@@ -1874,14 +1927,14 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         final List<File> indexDirectories = indexConfig.getIndexDirectories(
                 query.getStartDate() == null ? null : query.getStartDate().getTime(),
                         query.getEndDate() == null ? null : query.getEndDate().getTime());
-        final AsyncQuerySubmission result = new AsyncQuerySubmission(query, indexDirectories.size());
+        final AsyncQuerySubmission result = new AsyncQuerySubmission(query, indexDirectories.size(), userId);
         querySubmissionMap.put(query.getIdentifier(), result);
 
         if (indexDirectories.isEmpty()) {
             result.getResult().update(Collections.<ProvenanceEventRecord>emptyList(), 0L);
         } else {
             for (final File indexDir : indexDirectories) {
-                queryExecService.submit(new QueryRunnable(query, result, indexDir, retrievalCount));
+                queryExecService.submit(new QueryRunnable(query, result, user, indexDir, retrievalCount));
             }
         }
 
@@ -2054,13 +2107,13 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         };
     }
 
-    Lineage computeLineage(final String flowFileUuid) throws IOException {
-        return computeLineage(Collections.<String>singleton(flowFileUuid), LineageComputationType.FLOWFILE_LINEAGE, null, 0L, Long.MAX_VALUE);
+    Lineage computeLineage(final String flowFileUuid, final NiFiUser user) throws IOException {
+        return computeLineage(Collections.<String> singleton(flowFileUuid), user, LineageComputationType.FLOWFILE_LINEAGE, null, 0L, Long.MAX_VALUE);
     }
 
-    private Lineage computeLineage(final Collection<String> flowFileUuids, final LineageComputationType computationType, final Long eventId, final Long startTimestamp,
+    private Lineage computeLineage(final Collection<String> flowFileUuids, final NiFiUser user, final LineageComputationType computationType, final Long eventId, final Long startTimestamp,
             final Long endTimestamp) throws IOException {
-        final AsyncLineageSubmission submission = submitLineageComputation(flowFileUuids, computationType, eventId, startTimestamp, endTimestamp);
+        final AsyncLineageSubmission submission = submitLineageComputation(flowFileUuids, user, computationType, eventId, startTimestamp, endTimestamp);
         final StandardLineageResult result = submission.getResult();
         while (!result.isFinished()) {
             try {
@@ -2077,29 +2130,31 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public AsyncLineageSubmission submitLineageComputation(final String flowFileUuid) {
-        return submitLineageComputation(Collections.singleton(flowFileUuid), LineageComputationType.FLOWFILE_LINEAGE, null, 0L, Long.MAX_VALUE);
+    public AsyncLineageSubmission submitLineageComputation(final String flowFileUuid, final NiFiUser user) {
+        return submitLineageComputation(Collections.singleton(flowFileUuid), user, LineageComputationType.FLOWFILE_LINEAGE, null, 0L, Long.MAX_VALUE);
     }
 
-    private AsyncLineageSubmission submitLineageComputation(final Collection<String> flowFileUuids, final LineageComputationType computationType,
+    private AsyncLineageSubmission submitLineageComputation(final Collection<String> flowFileUuids, final NiFiUser user, final LineageComputationType computationType,
             final Long eventId, final long startTimestamp, final long endTimestamp) {
         final List<File> indexDirs = indexConfig.getIndexDirectories(startTimestamp, endTimestamp);
-        final AsyncLineageSubmission result = new AsyncLineageSubmission(computationType, eventId, flowFileUuids, indexDirs.size());
+        final AsyncLineageSubmission result = new AsyncLineageSubmission(computationType, eventId, flowFileUuids, indexDirs.size(), user.getIdentity());
         lineageSubmissionMap.put(result.getLineageIdentifier(), result);
 
         for (final File indexDir : indexDirs) {
-            queryExecService.submit(new ComputeLineageRunnable(flowFileUuids, result, indexDir));
+            queryExecService.submit(new ComputeLineageRunnable(flowFileUuids, user, result, indexDir));
         }
 
         return result;
     }
 
     @Override
-    public AsyncLineageSubmission submitExpandChildren(final long eventId) {
+    public AsyncLineageSubmission submitExpandChildren(final long eventId, final NiFiUser user) {
+        final String userId = user.getIdentity();
+
         try {
             final ProvenanceEventRecord event = getEvent(eventId);
             if (event == null) {
-                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
                 lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                 submission.getResult().update(Collections.<ProvenanceEventRecord>emptyList());
                 return submission;
@@ -2110,15 +2165,15 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
                 case FORK:
                 case JOIN:
                 case REPLAY:
-                    return submitLineageComputation(event.getChildUuids(), LineageComputationType.EXPAND_CHILDREN, eventId, event.getEventTime(), Long.MAX_VALUE);
+                    return submitLineageComputation(event.getChildUuids(), user, LineageComputationType.EXPAND_CHILDREN, eventId, event.getEventTime(), Long.MAX_VALUE);
                 default:
-                    final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+                    final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
                     lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                     submission.getResult().setError("Event ID " + eventId + " indicates an event of type " + event.getEventType() + " so its children cannot be expanded");
                     return submission;
             }
         } catch (final IOException ioe) {
-            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
             lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
 
             if (ioe.getMessage() == null) {
@@ -2132,11 +2187,13 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public AsyncLineageSubmission submitExpandParents(final long eventId) {
+    public AsyncLineageSubmission submitExpandParents(final long eventId, final NiFiUser user) {
+        final String userId = user.getIdentity();
+
         try {
             final ProvenanceEventRecord event = getEvent(eventId);
             if (event == null) {
-                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String>emptyList(), 1);
+                final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_CHILDREN, eventId, Collections.<String> emptyList(), 1, userId);
                 lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                 submission.getResult().update(Collections.<ProvenanceEventRecord>emptyList());
                 return submission;
@@ -2147,16 +2204,16 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
                 case FORK:
                 case CLONE:
                 case REPLAY:
-                    return submitLineageComputation(event.getParentUuids(), LineageComputationType.EXPAND_PARENTS, eventId, event.getLineageStartDate(), event.getEventTime());
+                    return submitLineageComputation(event.getParentUuids(), user, LineageComputationType.EXPAND_PARENTS, eventId, event.getLineageStartDate(), event.getEventTime());
                 default: {
-                    final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String>emptyList(), 1);
+                    final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String> emptyList(), 1, userId);
                     lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
                     submission.getResult().setError("Event ID " + eventId + " indicates an event of type " + event.getEventType() + " so its parents cannot be expanded");
                     return submission;
                 }
             }
         } catch (final IOException ioe) {
-            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String>emptyList(), 1);
+            final AsyncLineageSubmission submission = new AsyncLineageSubmission(LineageComputationType.EXPAND_PARENTS, eventId, Collections.<String> emptyList(), 1, userId);
             lineageSubmissionMap.put(submission.getLineageIdentifier(), submission);
 
             if (ioe.getMessage() == null) {
@@ -2170,17 +2227,47 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public AsyncLineageSubmission retrieveLineageSubmission(final String lineageIdentifier) {
-        return lineageSubmissionMap.get(lineageIdentifier);
+    public AsyncLineageSubmission retrieveLineageSubmission(final String lineageIdentifier, final NiFiUser user) {
+        final AsyncLineageSubmission submission = lineageSubmissionMap.get(lineageIdentifier);
+        final String userId = submission.getSubmitterIdentity();
+
+        if (user == null && userId == null) {
+            return submission;
+        }
+
+        if (user == null) {
+            throw new AccessDeniedException("Cannot retrieve Provenance Lineage Submission because no user id was provided");
+        }
+
+        if (userId == null || userId.equals(user.getIdentity())) {
+            return submission;
+        }
+
+        throw new AccessDeniedException("Cannot retrieve Provenance Lineage Submission because " + user.getIdentity() + " is not the user who submitted the request");
     }
 
     @Override
-    public QuerySubmission retrieveQuerySubmission(final String queryIdentifier) {
-        return querySubmissionMap.get(queryIdentifier);
+    public QuerySubmission retrieveQuerySubmission(final String queryIdentifier, final NiFiUser user) {
+        final QuerySubmission submission = querySubmissionMap.get(queryIdentifier);
+
+        final String userId = submission.getSubmitterIdentity();
+
+        if (user == null && userId == null) {
+            return submission;
+        }
+
+        if (user == null) {
+            throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because no user id was provided");
+        }
+
+        if (userId == null || userId.equals(user.getIdentity())) {
+            return submission;
+        }
+
+        throw new AccessDeniedException("Cannot retrieve Provenance Query Submission because " + user.getIdentity() + " is not the user who submitted the request");
     }
 
-    @Override
-    public ProvenanceEventRecord getEvent(final long id) throws IOException {
+    private ProvenanceEventRecord getEvent(final long id) throws IOException {
         final List<ProvenanceEventRecord> records = getEvents(id, 1);
         if (records.isEmpty()) {
             return null;
@@ -2192,6 +2279,17 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         return record;
     }
 
+    @Override
+    public ProvenanceEventRecord getEvent(final long id, final NiFiUser user) throws IOException {
+        final ProvenanceEventRecord event = getEvent(id);
+        if (event == null) {
+            return null;
+        }
+
+        authorize(event, user);
+        return event;
+    }
+
     private boolean needToRollover() {
         final long writtenSinceRollover = bytesWrittenSinceRollover.get();
 
@@ -2268,10 +2366,12 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
 
         private final Query query;
         private final AsyncQuerySubmission submission;
+        private final NiFiUser user;
 
-        public GetMostRecentRunnable(final Query query, final AsyncQuerySubmission submission) {
+        public GetMostRecentRunnable(final Query query, final AsyncQuerySubmission submission, final NiFiUser user) {
             this.query = query;
             this.submission = submission;
+            this.user = user;
         }
 
         @Override
@@ -2293,7 +2393,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
                 }
                 final long totalNumDocs = maxEventId - minIndexedId;
 
-                final List<ProvenanceEventRecord> mostRecent = getEvents(startIndex, maxResults);
+                final List<ProvenanceEventRecord> mostRecent = getEvents(startIndex, maxResults, user);
                 submission.getResult().update(mostRecent, totalNumDocs);
             } catch (final IOException ioe) {
                 logger.error("Failed to retrieve records from Provenance Repository: " + ioe.toString());
@@ -2314,12 +2414,14 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
 
         private final Query query;
         private final AsyncQuerySubmission submission;
+        private final NiFiUser user;
         private final File indexDir;
         private final AtomicInteger retrievalCount;
 
-        public QueryRunnable(final Query query, final AsyncQuerySubmission submission, final File indexDir, final AtomicInteger retrievalCount) {
+        public QueryRunnable(final Query query, final AsyncQuerySubmission submission, final NiFiUser user, final File indexDir, final AtomicInteger retrievalCount) {
             this.query = query;
             this.submission = submission;
+            this.user = user;
             this.indexDir = indexDir;
             this.retrievalCount = retrievalCount;
         }
@@ -2328,7 +2430,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
         public void run() {
             try {
                 final IndexSearch search = new IndexSearch(PersistentProvenanceRepository.this, indexDir, indexManager, maxAttributeChars);
-                final StandardQueryResult queryResult = search.search(query, retrievalCount, firstEventTimestamp);
+                final StandardQueryResult queryResult = search.search(query, user, retrievalCount, firstEventTimestamp);
                 submission.getResult().update(queryResult.getMatchingEvents(), queryResult.getTotalHitCount());
             } catch (final Throwable t) {
                 logger.error("Failed to query Provenance Repository Index {} due to {}", indexDir, t.toString());
@@ -2348,11 +2450,13 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
     private class ComputeLineageRunnable implements Runnable {
 
         private final Collection<String> flowFileUuids;
+        private final NiFiUser user;
         private final File indexDir;
         private final AsyncLineageSubmission submission;
 
-        public ComputeLineageRunnable(final Collection<String> flowFileUuids, final AsyncLineageSubmission submission, final File indexDir) {
+        public ComputeLineageRunnable(final Collection<String> flowFileUuids, final NiFiUser user, final AsyncLineageSubmission submission, final File indexDir) {
             this.flowFileUuids = flowFileUuids;
+            this.user = user;
             this.submission = submission;
             this.indexDir = indexDir;
         }
@@ -2368,7 +2472,7 @@ public class PersistentProvenanceRepository implements ProvenanceEventRepository
                     indexManager, indexDir, null, flowFileUuids, maxAttributeChars);
 
                 final StandardLineageResult result = submission.getResult();
-                result.update(matchingRecords);
+                result.update(replaceUnauthorizedWithPlaceholders(matchingRecords, user));
 
                 logger.info("Successfully created Lineage for FlowFiles with UUIDs {} in {} milliseconds; Lineage contains {} nodes and {} edges",
                         flowFileUuids, result.getComputationTime(TimeUnit.MILLISECONDS), result.getNodes().size(), result.getEdges().size());

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/authorization/AuthorizationCheck.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/authorization/AuthorizationCheck.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/authorization/AuthorizationCheck.java
new file mode 100644
index 0000000..3627572
--- /dev/null
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/authorization/AuthorizationCheck.java
@@ -0,0 +1,24 @@
+/*
+ * 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.provenance.authorization;
+
+import org.apache.nifi.provenance.ProvenanceEventRecord;
+
+public interface AuthorizationCheck {
+    boolean isAuthorized(ProvenanceEventRecord event);
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/DocsReader.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/DocsReader.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/DocsReader.java
index b195559..e448f27 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/DocsReader.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/DocsReader.java
@@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.nifi.provenance.ProvenanceEventRecord;
 import org.apache.nifi.provenance.SearchableFields;
 import org.apache.nifi.provenance.StandardProvenanceEventRecord;
+import org.apache.nifi.provenance.authorization.AuthorizationCheck;
 import org.apache.nifi.provenance.serialization.RecordReader;
 import org.apache.nifi.provenance.serialization.RecordReaders;
 import org.apache.nifi.provenance.toc.TocReader;
@@ -47,7 +48,7 @@ import org.slf4j.LoggerFactory;
 class DocsReader {
     private final Logger logger = LoggerFactory.getLogger(DocsReader.class);
 
-    public Set<ProvenanceEventRecord> read(final TopDocs topDocs, final IndexReader indexReader, final Collection<Path> allProvenanceLogFiles,
+    public Set<ProvenanceEventRecord> read(final TopDocs topDocs, final AuthorizationCheck authCheck, final IndexReader indexReader, final Collection<Path> allProvenanceLogFiles,
             final AtomicInteger retrievalCount, final int maxResults, final int maxAttributeChars) throws IOException {
         if (retrievalCount.get() >= maxResults) {
             return Collections.emptySet();
@@ -65,7 +66,7 @@ class DocsReader {
 
         final long readDocuments = System.nanoTime() - start;
         logger.debug("Reading {} Lucene Documents took {} millis", docs.size(), TimeUnit.NANOSECONDS.toMillis(readDocuments));
-        return read(docs, allProvenanceLogFiles, retrievalCount, maxResults, maxAttributeChars);
+        return read(docs, authCheck, allProvenanceLogFiles, retrievalCount, maxResults, maxAttributeChars);
     }
 
 
@@ -104,7 +105,7 @@ class DocsReader {
         return record;
     }
 
-    public Set<ProvenanceEventRecord> read(final List<Document> docs, final Collection<Path> allProvenanceLogFiles,
+    public Set<ProvenanceEventRecord> read(final List<Document> docs, final AuthorizationCheck authCheck, final Collection<Path> allProvenanceLogFiles,
             final AtomicInteger retrievalCount, final int maxResults, final int maxAttributeChars) throws IOException {
 
         if (retrievalCount.get() >= maxResults) {
@@ -128,9 +129,9 @@ class DocsReader {
 
                     Iterator<Document> docIter = byStorageNameDocGroups.get(storageFileName).iterator();
                     while (docIter.hasNext() && retrievalCount.getAndIncrement() < maxResults) {
-                        ProvenanceEventRecord eRec = this.getRecord(docIter.next(), reader);
-                        if (eRec != null) {
-                            matchingRecords.add(eRec);
+                        ProvenanceEventRecord event = this.getRecord(docIter.next(), reader);
+                        if (event != null && authCheck.isAuthorized(event)) {
+                            matchingRecords.add(event);
                             eventsReadThisFile++;
                         }
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/IndexSearch.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/IndexSearch.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/IndexSearch.java
index 65a06ac..00e5f38 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/IndexSearch.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/IndexSearch.java
@@ -28,9 +28,11 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TopDocs;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.provenance.PersistentProvenanceRepository;
 import org.apache.nifi.provenance.ProvenanceEventRecord;
 import org.apache.nifi.provenance.StandardQueryResult;
+import org.apache.nifi.provenance.authorization.AuthorizationCheck;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -48,7 +50,8 @@ public class IndexSearch {
         this.maxAttributeChars = maxAttributeChars;
     }
 
-    public StandardQueryResult search(final org.apache.nifi.provenance.search.Query provenanceQuery, final AtomicInteger retrievedCount, final long firstEventTimestamp) throws IOException {
+    public StandardQueryResult search(final org.apache.nifi.provenance.search.Query provenanceQuery, final NiFiUser user, final AtomicInteger retrievedCount,
+        final long firstEventTimestamp) throws IOException {
         if (retrievedCount.get() >= provenanceQuery.getMaxResults()) {
             final StandardQueryResult sqr = new StandardQueryResult(provenanceQuery, 1);
             sqr.update(Collections.<ProvenanceEventRecord> emptyList(), 0L);
@@ -102,7 +105,10 @@ public class IndexSearch {
             }
 
             final DocsReader docsReader = new DocsReader();
-            matchingRecords = docsReader.read(topDocs, searcher.getIndexReader(), repository.getAllLogFiles(), retrievedCount,
+
+            final AuthorizationCheck authCheck = event -> repository.isAuthorized(event, user);
+
+            matchingRecords = docsReader.read(topDocs, authCheck, searcher.getIndexReader(), repository.getAllLogFiles(), retrievedCount,
                 provenanceQuery.getMaxResults(), maxAttributeChars);
 
             final long readRecordsNanos = System.nanoTime() - finishSearch;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/LineageQuery.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/LineageQuery.java b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/LineageQuery.java
index ce60e03..3a2d6e1 100644
--- a/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/LineageQuery.java
+++ b/nifi-nar-bundles/nifi-provenance-repository-bundle/nifi-persistent-provenance-repository/src/main/java/org/apache/nifi/provenance/lucene/LineageQuery.java
@@ -36,6 +36,7 @@ import org.apache.lucene.search.TopDocs;
 import org.apache.nifi.provenance.PersistentProvenanceRepository;
 import org.apache.nifi.provenance.ProvenanceEventRecord;
 import org.apache.nifi.provenance.SearchableFields;
+import org.apache.nifi.provenance.authorization.AuthorizationCheck;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -93,8 +94,12 @@ public class LineageQuery {
                 final TopDocs uuidQueryTopDocs = searcher.search(query, MAX_QUERY_RESULTS);
                 final long searchEnd = System.nanoTime();
 
+                // Always authorized. We do this because we need to pull back the event, regardless of whether or not
+                // the user is truly authorized, because instead of ignoring unauthorized events, we want to replace them.
+                final AuthorizationCheck authCheck = event -> true;
+
                 final DocsReader docsReader = new DocsReader();
-                final Set<ProvenanceEventRecord> recs = docsReader.read(uuidQueryTopDocs, searcher.getIndexReader(), repo.getAllLogFiles(),
+                final Set<ProvenanceEventRecord> recs = docsReader.read(uuidQueryTopDocs, authCheck, searcher.getIndexReader(), repo.getAllLogFiles(),
                     new AtomicInteger(0), Integer.MAX_VALUE, maxAttributeChars);
 
                 final long readDocsEnd = System.nanoTime();


[4/4] nifi git commit: NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592

Posted by mc...@apache.org.
NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592


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

Branch: refs/heads/master
Commit: ae9e2fdf0bfce31c38020784b78171709618903c
Parents: 65d8958
Author: Mark Payne <ma...@hotmail.com>
Authored: Tue Jun 28 14:53:35 2016 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Thu Jun 30 07:57:17 2016 -0400

----------------------------------------------------------------------
 .../authorization/AccessDeniedException.java    |  39 ++
 .../authorization/resource/Authorizable.java    | 125 ++++++
 .../nifi/authorization/user/NiFiUser.java       |  44 ++
 .../ProvenanceAuthorizableFactory.java          |  35 ++
 .../provenance/ProvenanceEventRepository.java   |  98 +++--
 .../nifi/provenance/ProvenanceEventType.java    |   8 +-
 .../lineage/ComputeLineageSubmission.java       |   5 +
 .../nifi/provenance/search/QuerySubmission.java |   5 +
 .../nifi/provenance/AsyncLineageSubmission.java |   9 +-
 .../nifi/provenance/AsyncQuerySubmission.java   |   9 +-
 .../provenance/PlaceholderProvenanceEvent.java  | 196 +++++++++
 .../nifi/provenance/StandardLineageResult.java  |   8 +-
 .../nifi/provenance/StandardQueryResult.java    |  14 +-
 .../MockProvenanceEventRepository.java          |  24 +-
 .../api/dto/provenance/lineage/LineageDTO.java  |  15 -
 .../provenance/lineage/LineageRequestDTO.java   |  13 +
 .../authorization/AccessDeniedException.java    |  39 --
 .../authorization/resource/Authorizable.java    | 141 -------
 .../resource/ProvenanceEventAuthorizable.java   |  41 ++
 .../authorization/resource/ResourceFactory.java |  25 +-
 .../authorization/resource/ResourceType.java    |   1 +
 .../nifi/authorization/user/NiFiUser.java       |  93 -----
 .../authorization/user/StandardNiFiUser.java    |  94 +++++
 .../org/apache/nifi/controller/Template.java    |  15 +-
 .../apache/nifi/controller/FlowController.java  | 107 +++--
 .../nifi/web/StandardNiFiServiceFacade.java     |   2 +-
 .../StandardNiFiWebConfigurationContext.java    |  18 +-
 .../nifi/web/api/AccessPolicyResource.java      |   9 +-
 .../nifi/web/api/ApplicationResource.java       |   4 +-
 .../apache/nifi/web/api/ConnectionResource.java |   7 +-
 .../nifi/web/api/ControllerServiceResource.java |  73 ++--
 .../nifi/web/api/FlowFileQueueResource.java     |  17 +-
 .../org/apache/nifi/web/api/FlowResource.java   |  66 +--
 .../org/apache/nifi/web/api/FunnelResource.java |   7 +-
 .../apache/nifi/web/api/InputPortResource.java  |   7 +-
 .../org/apache/nifi/web/api/LabelResource.java  |   7 +-
 .../apache/nifi/web/api/OutputPortResource.java |   7 +-
 .../nifi/web/api/ProcessGroupResource.java      | 125 +++---
 .../apache/nifi/web/api/ProcessorResource.java  |  13 +-
 .../apache/nifi/web/api/ProvenanceResource.java |   8 +-
 .../web/api/RemoteProcessGroupResource.java     |  11 +-
 .../nifi/web/api/ReportingTaskResource.java     |  13 +-
 .../apache/nifi/web/api/SnippetResource.java    |   3 +-
 .../apache/nifi/web/api/TemplateResource.java   |   5 +-
 .../apache/nifi/web/api/TenantsResource.java    |  21 +-
 .../api/config/AccessDeniedExceptionMapper.java |   8 +-
 .../org/apache/nifi/web/api/dto/DtoFactory.java |   7 +-
 .../nifi/web/controller/ControllerFacade.java   |  96 ++---
 .../web/dao/impl/StandardConnectionDAO.java     |   4 +-
 .../web/StandardNiFiServiceFacadeSpec.groovy    |   9 +-
 .../web/revision/TestNaiveRevisionManager.java  |   7 +-
 .../anonymous/NiFiAnonymousUserFilter.java      |   8 +-
 .../security/jwt/JwtAuthenticationProvider.java |   6 +-
 .../security/otp/OtpAuthenticationProvider.java |   3 +-
 .../security/token/NiFiAuthenticationToken.java |   5 +
 .../x509/X509AuthenticationProvider.java        |   5 +-
 .../js/nf/provenance/nf-provenance-lineage.js   |   8 +-
 .../js/nf/provenance/nf-provenance-table.js     |   4 +-
 .../webapp/js/nf/provenance/nf-provenance.js    |  25 +-
 .../src/main/webapp/js/nf/summary/nf-summary.js |  23 +-
 .../PersistentProvenanceRepository.java         | 188 +++++++--
 .../authorization/AuthorizationCheck.java       |  24 ++
 .../nifi/provenance/lucene/DocsReader.java      |  13 +-
 .../nifi/provenance/lucene/IndexSearch.java     |  10 +-
 .../nifi/provenance/lucene/LineageQuery.java    |   7 +-
 .../TestPersistentProvenanceRepository.java     | 400 +++++++++++++++++--
 .../VolatileProvenanceRepository.java           | 168 ++++++--
 .../TestVolatileProvenanceRepository.java       |  28 +-
 68 files changed, 1832 insertions(+), 850 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
new file mode 100644
index 0000000..8712d28
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authorization;
+
+/**
+ * Represents any error that might occur while authorizing user requests.
+ */
+public class AccessDeniedException extends RuntimeException {
+    private static final long serialVersionUID = -5683444815269084134L;
+
+    public AccessDeniedException(Throwable cause) {
+        super(cause);
+    }
+
+    public AccessDeniedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AccessDeniedException(String message) {
+        super(message);
+    }
+
+    public AccessDeniedException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
new file mode 100644
index 0000000..09fab19
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
@@ -0,0 +1,125 @@
+/*
+ * 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.authorization.resource;
+
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.user.NiFiUser;
+
+public interface Authorizable {
+
+    /**
+     * The parent for this Authorizable. May be null.
+     *
+     * @return the parent authorizable or null
+     */
+    Authorizable getParentAuthorizable();
+
+    /**
+     * The Resource for this Authorizable.
+     *
+     * @return the parent resource
+     */
+    Resource getResource();
+
+    /**
+     * Returns whether the current user is authorized for the specified action on the specified resource. This
+     * method does not imply the user is directly attempting to access the specified resource. If the user is
+     * attempting a direct access use Authorizable.authorize().
+     *
+     * @param authorizer authorizer
+     * @param action action
+     * @return is authorized
+     */
+    default boolean isAuthorized(Authorizer authorizer, RequestAction action, NiFiUser user) {
+        return Result.Approved.equals(checkAuthorization(authorizer, action, user).getResult());
+    }
+
+    /**
+     * Returns the result of an authorization request for the specified user for the specified action on the specified
+     * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is
+     * attempting a direct access use Authorizable.authorize().
+     *
+     * @param authorizer authorizer
+     * @param action action
+     * @param user user
+     * @return is authorized
+     */
+    default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user) {
+        // TODO - include user details context
+
+        // build the request
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+                .identity(user.getIdentity())
+                .anonymous(user.isAnonymous())
+                .accessAttempt(false)
+                .action(action)
+                .resource(getResource())
+                .build();
+
+        // perform the authorization
+        final AuthorizationResult result = authorizer.authorize(request);
+
+        // verify the results
+        if (Result.ResourceNotFound.equals(result.getResult())) {
+            final Authorizable parent = getParentAuthorizable();
+            if (parent == null) {
+                return AuthorizationResult.denied();
+            } else {
+                return parent.checkAuthorization(authorizer, action, user);
+            }
+        } else {
+            return result;
+        }
+    }
+
+    /**
+     * Authorizes the current user for the specified action on the specified resource. This method does imply the user is
+     * directly accessing the specified resource.
+     *
+     * @param authorizer authorizer
+     * @param action action
+     */
+    default void authorize(Authorizer authorizer, RequestAction action, NiFiUser user) throws AccessDeniedException {
+        // TODO - include user details context
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+            .identity(user.getIdentity())
+            .anonymous(user.isAnonymous())
+            .accessAttempt(true)
+            .action(action)
+            .resource(getResource())
+            .build();
+
+        final AuthorizationResult result = authorizer.authorize(request);
+        if (Result.ResourceNotFound.equals(result.getResult())) {
+            final Authorizable parent = getParentAuthorizable();
+            if (parent == null) {
+                throw new AccessDeniedException("Access is denied");
+            } else {
+                parent.authorize(authorizer, action, user);
+            }
+        } else if (Result.Denied.equals(result.getResult())) {
+            throw new AccessDeniedException(result.getExplanation());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
new file mode 100644
index 0000000..d5dee54
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
@@ -0,0 +1,44 @@
+/*
+ * 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.authorization.user;
+
+/**
+ * A representation of a NiFi user that has logged into the application
+ */
+public interface NiFiUser {
+
+    /**
+     * @return the unique identity of this user
+     */
+    String getIdentity();
+
+    /**
+     * @return the user name for this user
+     */
+    String getUserName();
+
+    /**
+     * @return the next user in the proxied entities chain, or <code>null</code> if no more users exist in the chain.
+     */
+    NiFiUser getChain();
+
+    /**
+     * @return <code>true</code> if the user is the unauthenticated Anonymous user
+     */
+    boolean isAnonymous();
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java
new file mode 100644
index 0000000..23d6b3d
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.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.provenance;
+
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.web.ResourceNotFoundException;
+
+public interface ProvenanceAuthorizableFactory {
+
+    /**
+     * Generates an Authorizable object for the Provenance events of the component with the given ID
+     *
+     * @param componentId the ID of the component to which the Provenance events belong
+     *
+     * @return the Authorizable that can be use to authorize access to provenance events
+     * @throws ResourceNotFoundException if no component can be found with the given ID
+     */
+    Authorizable createProvenanceAuthorizable(String componentId);
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java
index 25563b7..235a1fa 100644
--- a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java
+++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java
@@ -19,11 +19,15 @@ package org.apache.nifi.provenance;
 import java.io.IOException;
 import java.util.List;
 
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.provenance.lineage.ComputeLineageSubmission;
 import org.apache.nifi.provenance.search.Query;
 import org.apache.nifi.provenance.search.QuerySubmission;
 import org.apache.nifi.provenance.search.SearchableField;
+import org.apache.nifi.web.ResourceNotFoundException;
 
 /**
  * This Repository houses Provenance Events. The repository is responsible for
@@ -38,9 +42,12 @@ public interface ProvenanceEventRepository {
      * framework.
      *
      * @param eventReporter to report to
+     * @param authorizer the authorizer to use for authorizing individual events
+     * @param resourceFactory the resource factory to use for generating Provenance Resource objects for authorization purposes
+     *
      * @throws java.io.IOException if unable to initialize
      */
-    void initialize(EventReporter eventReporter) throws IOException;
+    void initialize(EventReporter eventReporter, Authorizer authorizer, ProvenanceAuthorizableFactory resourceFactory) throws IOException;
 
     /**
      * Returns a {@link ProvenanceEventBuilder} that is capable of building
@@ -74,7 +81,8 @@ public interface ProvenanceEventRepository {
     /**
      * Returns a List of all <code>ProvenanceEventRecord</code>s in the
      * repository starting with the given ID. The first ID in the repository
-     * will always be 0 or higher.
+     * will always be 0 or higher. This method performs no authorization of
+     * the events.
      *
      * @param firstRecordId id of the first record to retrieve
      * @param maxRecords maximum number of records to retrieve
@@ -84,8 +92,24 @@ public interface ProvenanceEventRepository {
     List<ProvenanceEventRecord> getEvents(long firstRecordId, final int maxRecords) throws IOException;
 
     /**
+     * Returns a List of all <code>ProvenanceEventRecord</code>s in the
+     * repository starting with the given ID. The first ID in the repository
+     * will always be 0 or higher. Each event that is found will be authorized
+     * against the given NiFiUser. If the user does not have authorization for
+     * the event, the event will not be returned.
+     *
+     * @param firstRecordId id of the first record to retrieve
+     * @param maxRecords maximum number of records to retrieve
+     * @param user the NiFi user that the events should be authorized against
+     *
+     * @return records
+     * @throws java.io.IOException if error reading from repository
+     */
+    List<ProvenanceEventRecord> getEvents(long firstRecordId, final int maxRecords, NiFiUser user) throws IOException;
+
+    /**
      * @return the largest ID of any event that is queryable in the repository.
-     * If no queryable events exists, returns null
+     *         If no queryable events exists, returns null
      */
     Long getMaxEventId();
 
@@ -94,70 +118,96 @@ public interface ProvenanceEventRepository {
      * identifier that can be used to fetch the results at a later time
      *
      * @param query to submit
+     * @param user the NiFi User to authorize the events against
+     *
      * @return an identifier that can be used to fetch the results at a later
-     * time
+     *         time
      */
-    QuerySubmission submitQuery(Query query);
+    QuerySubmission submitQuery(Query query, NiFiUser user);
 
     /**
      * @param queryIdentifier of the query
+     * @param user the user who is retrieving the query
      *
      * @return the QueryResult associated with the given identifier, if the
-     * query has finished processing. If the query has not yet finished running,
-     * returns <code>null</code>
+     *         query has finished processing. If the query has not yet finished running,
+     *         returns <code>null</code>
      */
-    QuerySubmission retrieveQuerySubmission(String queryIdentifier);
+    QuerySubmission retrieveQuerySubmission(String queryIdentifier, NiFiUser user);
 
     /**
      * Submits a Lineage Computation to be completed and returns the
      * AsynchronousLineageResult that indicates the status of the request and
-     * the results, if the computation is complete.
+     * the results, if the computation is complete. If the given user does not
+     * have authorization to view one of the events in the lineage, a placeholder
+     * event will be used instead that provides none of the event details except
+     * for the identifier of the component that emitted the Provenance Event. It is
+     * necessary to include this node in the lineage view so that the lineage makes
+     * sense, rather than showing disconnected graphs when the user is not authorized
+     * for all components' provenance events.
      *
      * @param flowFileUuid the UUID of the FlowFile for which the Lineage should
-     * be calculated
+     *            be calculated
+     * @param user the NiFi User to authorize events against
+     *
      * @return a {@link ComputeLineageSubmission} object that can be used to
-     * check if the computing is complete and if so get the results
+     *         check if the computing is complete and if so get the results
      */
-    ComputeLineageSubmission submitLineageComputation(String flowFileUuid);
+    ComputeLineageSubmission submitLineageComputation(String flowFileUuid, NiFiUser user);
 
     /**
      * @param lineageIdentifier identifier of lineage to compute
+     * @param user the user who is retrieving the lineage submission
+     *
      * @return the {@link ComputeLineageSubmission} associated with the given
-     * identifier
+     *         identifier
      */
-    ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier);
+    ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier, NiFiUser user);
 
     /**
+     * Retrieves the Provenance Event with the given ID. The event will be returned only
+     * if the given user is authorized to access the event. Otherwise, an
+     * AccessDeniedException or ResourceNotFoundException will be thrown, as appropriate
+     *
      * @param id to lookup
      * @return the Provenance Event Record with the given ID, if it exists, or
-     * {@code null} otherwise
+     *         {@code null} otherwise
      * @throws IOException if failure while retrieving event
+     * @throws AccessDeniedException if the user does not have access to the component
+     * @throws ResourceNotFoundException if the component that the event belongs to cannot be found
      */
-    ProvenanceEventRecord getEvent(long id) throws IOException;
+    ProvenanceEventRecord getEvent(long id, NiFiUser user) throws IOException;
 
     /**
-     * Submits a request to expand the parents of the event with the given id
+     * Submits a request to expand the parents of the event with the given id. If the given user
+     * is not authorized to access any event, a placeholder will be used instead that contains only
+     * the ID of the component that emitted the event.
      *
      * @param eventId the one-up id of the Event to expand
+     * @param user the NiFi user to authorize events against
      * @return a submission which can be checked for status
      *
      * @throws IllegalArgumentException if the given identifier identifies a
-     * Provenance Event that has a Type that is not expandable or if the
-     * identifier cannot be found
+     *             Provenance Event that has a Type that is not expandable or if the
+     *             identifier cannot be found
      */
-    ComputeLineageSubmission submitExpandParents(long eventId);
+    ComputeLineageSubmission submitExpandParents(long eventId, NiFiUser user);
 
     /**
-     * Submits a request to expand the children of the event with the given id
+     * Submits a request to expand the children of the event with the given id. If the given user
+     * is not authorized to access any event, a placeholder will be used instead that contains only
+     * the ID of the component that emitted the event.
      *
      * @param eventId the one-up id of the Event
+     * @param user the NiFi user to authorize events against
+     *
      * @return a submission which can be checked for status
      *
      * @throws IllegalArgumentException if the given identifier identifies a
-     * Provenance Event that has a Type that is not expandable or if the
-     * identifier cannot be found
+     *             Provenance Event that has a Type that is not expandable or if the
+     *             identifier cannot be found
      */
-    ComputeLineageSubmission submitExpandChildren(long eventId);
+    ComputeLineageSubmission submitExpandChildren(long eventId, NiFiUser user);
 
     /**
      * Closes the repository, freeing any resources

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java
index 0d844b8..756d362 100644
--- a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java
+++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java
@@ -117,5 +117,11 @@ public enum ProvenanceEventType {
      * that is the UUID of the a newly created FlowFile that will be re-queued
      * for processing.
      */
-    REPLAY
+    REPLAY,
+
+    /**
+     * Indicates that the type of the provenance event is unknown because the user
+     * who is attempting to access the event is not authorize to know the type.
+     */
+    UNKNOWN;
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java b/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java
index a9df26c..8a11523 100644
--- a/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java
+++ b/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java
@@ -34,6 +34,11 @@ public interface ComputeLineageSubmission {
     Date getSubmissionTime();
 
     /**
+     * @return the identity of the user who submitted the request
+     */
+    String getSubmitterIdentity();
+
+    /**
      * @return the generated identifier for this lineage result
      */
     String getLineageIdentifier();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java b/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java
index 4716d2d..45efe4b 100644
--- a/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java
+++ b/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java
@@ -52,4 +52,9 @@ public interface QuerySubmission {
      * <code>false</code> otherwise
      */
     boolean isCanceled();
+
+    /**
+     * @return the identity of the user who submitted the query
+     */
+    String getSubmitterIdentity();
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java
index 4a52a89..82bb542 100644
--- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java
+++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java
@@ -34,19 +34,26 @@ public class AsyncLineageSubmission implements ComputeLineageSubmission {
     private final LineageComputationType computationType;
     private final Long eventId;
     private final Collection<String> lineageFlowFileUuids;
+    private final String submitterId;
 
     private volatile boolean canceled = false;
 
     private final StandardLineageResult result;
 
-    public AsyncLineageSubmission(final LineageComputationType computationType, final Long eventId, final Collection<String> lineageFlowFileUuids, final int numSteps) {
+    public AsyncLineageSubmission(final LineageComputationType computationType, final Long eventId, final Collection<String> lineageFlowFileUuids, final int numSteps, final String submitterId) {
         this.computationType = computationType;
         this.eventId = eventId;
         this.lineageFlowFileUuids = lineageFlowFileUuids;
+        this.submitterId = submitterId;
         this.result = new StandardLineageResult(numSteps, lineageFlowFileUuids);
     }
 
     @Override
+    public String getSubmitterIdentity() {
+        return submitterId;
+    }
+
+    @Override
     public StandardLineageResult getResult() {
         return result;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java
index 00c6170..cd2ab39 100644
--- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java
+++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java
@@ -31,6 +31,7 @@ public class AsyncQuerySubmission implements QuerySubmission {
 
     private volatile boolean canceled = false;
     private final StandardQueryResult queryResult;
+    private final String submitterId;
 
     /**
      * Constructs an AsyncQuerySubmission with the given query and the given
@@ -40,12 +41,18 @@ public class AsyncQuerySubmission implements QuerySubmission {
      * @param query the query to execute
      * @param numSteps how many steps to include
      */
-    public AsyncQuerySubmission(final Query query, final int numSteps) {
+    public AsyncQuerySubmission(final Query query, final int numSteps, final String submitterId) {
         this.query = query;
+        this.submitterId = submitterId;
         queryResult = new StandardQueryResult(query, numSteps);
     }
 
     @Override
+    public String getSubmitterIdentity() {
+        return submitterId;
+    }
+
+    @Override
     public Date getSubmissionTime() {
         return submissionTime;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java
new file mode 100644
index 0000000..bc40302
--- /dev/null
+++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java
@@ -0,0 +1,196 @@
+/*
+ * 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.provenance;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Provenance Event that is used to replace another Provenance Event when authorizations
+ * are not granted for the original Provenance Event
+ */
+public class PlaceholderProvenanceEvent implements ProvenanceEventRecord {
+    private final String componentId;
+    private final long eventId;
+    private final long eventTime;
+    private final String flowFileUuid;
+
+    public PlaceholderProvenanceEvent(final ProvenanceEventRecord original) {
+        this.componentId = original.getComponentId();
+        this.eventId = original.getEventId();
+        this.eventTime = original.getEventTime();
+        this.flowFileUuid = original.getFlowFileUuid();
+    }
+
+    @Override
+    public long getEventId() {
+        return eventId;
+    }
+
+    @Override
+    public long getEventTime() {
+        return eventTime;
+    }
+
+    @Override
+    public long getFlowFileEntryDate() {
+        return 0;
+    }
+
+    @Override
+    public long getLineageStartDate() {
+        return 0;
+    }
+
+    @Override
+    public Set<String> getLineageIdentifiers() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public long getFileSize() {
+        return -1L;
+    }
+
+    @Override
+    public Long getPreviousFileSize() {
+        return -1L;
+    }
+
+    @Override
+    public long getEventDuration() {
+        return -1L;
+    }
+
+    @Override
+    public ProvenanceEventType getEventType() {
+        return ProvenanceEventType.UNKNOWN;
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<String, String> getPreviousAttributes() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<String, String> getUpdatedAttributes() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public String getComponentId() {
+        return componentId;
+    }
+
+    @Override
+    public String getComponentType() {
+        return null;
+    }
+
+    @Override
+    public String getTransitUri() {
+        return null;
+    }
+
+    @Override
+    public String getSourceSystemFlowFileIdentifier() {
+        return null;
+    }
+
+    @Override
+    public String getFlowFileUuid() {
+        return flowFileUuid;
+    }
+
+    @Override
+    public List<String> getParentUuids() {
+        return null;
+    }
+
+    @Override
+    public List<String> getChildUuids() {
+        return null;
+    }
+
+    @Override
+    public String getAlternateIdentifierUri() {
+        return null;
+    }
+
+    @Override
+    public String getDetails() {
+        return null;
+    }
+
+    @Override
+    public String getRelationship() {
+        return null;
+    }
+
+    @Override
+    public String getSourceQueueIdentifier() {
+        return null;
+    }
+
+    @Override
+    public String getContentClaimSection() {
+        return null;
+    }
+
+    @Override
+    public String getPreviousContentClaimSection() {
+        return null;
+    }
+
+    @Override
+    public String getContentClaimContainer() {
+        return null;
+    }
+
+    @Override
+    public String getPreviousContentClaimContainer() {
+        return null;
+    }
+
+    @Override
+    public String getContentClaimIdentifier() {
+        return null;
+    }
+
+    @Override
+    public String getPreviousContentClaimIdentifier() {
+        return null;
+    }
+
+    @Override
+    public Long getContentClaimOffset() {
+        return null;
+    }
+
+    @Override
+    public Long getPreviousContentClaimOffset() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java
index 02c089d..78b3188 100644
--- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java
+++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java
@@ -268,7 +268,7 @@ public class StandardLineageResult implements ComputeLineageResult {
                             final boolean isNewFlowFile = nodes.add(childNode);
                             if (!isNewFlowFile) {
                                 final String msg = "Unable to generate Lineage Graph because multiple "
-                                        + "events were registered claiming to have generated the same FlowFile (UUID = " + childNode.getFlowFileUuid() + ")";
+                                    + "events were registered claiming to have generated the same FlowFile (UUID = " + childNode.getFlowFileUuid() + ")";
                                 logger.error(msg);
                                 setError(msg);
                                 return;
@@ -287,7 +287,7 @@ public class StandardLineageResult implements ComputeLineageResult {
                         lastEventMap.put(parentUuid, lineageNode);
                     }
                 }
-                break;
+                    break;
                 case RECEIVE:
                 case CREATE: {
                     // for a receive event, we want to create a FlowFile Node that represents the FlowFile received
@@ -296,7 +296,7 @@ public class StandardLineageResult implements ComputeLineageResult {
                     final boolean isNewFlowFile = nodes.add(flowFileNode);
                     if (!isNewFlowFile) {
                         final String msg = "Found cycle in graph. This indicates that multiple events "
-                                + "were registered claiming to have generated the same FlowFile (UUID = " + flowFileNode.getFlowFileUuid() + ")";
+                            + "were registered claiming to have generated the same FlowFile (UUID = " + flowFileNode.getFlowFileUuid() + ")";
                         setError(msg);
                         logger.error(msg);
                         return;
@@ -304,7 +304,7 @@ public class StandardLineageResult implements ComputeLineageResult {
                     edges.add(new EdgeNode(record.getFlowFileUuid(), lineageNode, flowFileNode));
                     lastEventMap.put(record.getFlowFileUuid(), flowFileNode);
                 }
-                break;
+                    break;
                 default:
                     break;
             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java
index 03ab3ea..5c09e8e 100644
--- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java
+++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java
@@ -90,7 +90,19 @@ public class StandardQueryResult implements QueryResult {
     public long getTotalHitCount() {
         readLock.lock();
         try {
-            return totalHitCount;
+            // Because we filter the results based on the user's permissions,
+            // we don't want to indicate that the total hit count is 1,000+ when we
+            // have 0 matching records, for instance. So, if we have fewer matching
+            // records than the max specified by the query, it is either the case that
+            // we truly don't have enough records to reach the max results, or that
+            // the user is not authorized to see some of the results. Either way,
+            // we want to report the number of events that we find AND that the user
+            // is allowed to see, so we report matching record count, or up to max results.
+            if (matchingRecords.size() < query.getMaxResults()) {
+                return matchingRecords.size();
+            } else {
+                return query.getMaxResults();
+            }
         } finally {
             readLock.unlock();
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java
----------------------------------------------------------------------
diff --git a/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java b/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java
index 241041a..dc71ed5 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java
@@ -22,6 +22,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.provenance.lineage.ComputeLineageSubmission;
 import org.apache.nifi.provenance.search.Query;
@@ -54,7 +56,8 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public void initialize(EventReporter reporter) throws IOException {
+    public void initialize(EventReporter eventReporter, Authorizer authorizer, ProvenanceAuthorizableFactory resourceFactory) throws IOException {
+
     }
 
     @Override
@@ -67,32 +70,37 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository
     }
 
     @Override
+    public List<ProvenanceEventRecord> getEvents(long firstRecordId, int maxRecords, NiFiUser user) throws IOException {
+        return getEvents(firstRecordId, maxRecords);
+    }
+
+    @Override
     public Long getMaxEventId() {
         return Long.valueOf(records.size() - 1);
     }
 
     @Override
-    public QuerySubmission submitQuery(Query query) {
+    public QuerySubmission submitQuery(Query query, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support querying");
     }
 
     @Override
-    public QuerySubmission retrieveQuerySubmission(String queryIdentifier) {
+    public QuerySubmission retrieveQuerySubmission(String queryIdentifier, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support querying");
     }
 
     @Override
-    public ComputeLineageSubmission submitLineageComputation(String flowFileUuid) {
+    public ComputeLineageSubmission submitLineageComputation(String flowFileUuid, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation");
     }
 
     @Override
-    public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier) {
+    public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation");
     }
 
     @Override
-    public ProvenanceEventRecord getEvent(long id) throws IOException {
+    public ProvenanceEventRecord getEvent(long id, NiFiUser user) throws IOException {
         if (id > records.size()) {
             return null;
         }
@@ -101,12 +109,12 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository
     }
 
     @Override
-    public ComputeLineageSubmission submitExpandParents(long eventId) {
+    public ComputeLineageSubmission submitExpandParents(long eventId, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation");
     }
 
     @Override
-    public ComputeLineageSubmission submitExpandChildren(long eventId) {
+    public ComputeLineageSubmission submitExpandChildren(long eventId, NiFiUser user) {
         throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation");
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java
index bc68d78..46d99bf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java
@@ -30,7 +30,6 @@ public class LineageDTO {
 
     private String id;
     private String uri;
-    private String clusterNodeId;
 
     private Date submissionTime;
     private Date expiration;
@@ -69,20 +68,6 @@ public class LineageDTO {
     }
 
     /**
-     * @return id of the node in the cluster where this lineage originated
-     */
-    @ApiModelProperty(
-            value = "The id of the node where this lineage originated if clustered."
-    )
-    public String getClusterNodeId() {
-        return clusterNodeId;
-    }
-
-    public void setClusterNodeId(String clusterNodeId) {
-        this.clusterNodeId = clusterNodeId;
-    }
-
-    /**
      * @return submission time for this lineage
      */
     @XmlJavaTypeAdapter(TimestampAdapter.class)

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java
index afab621..5a59a7c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java
@@ -41,6 +41,7 @@ public class LineageRequestDTO {
     private LineageRequestType lineageRequestType;
 
     private String uuid;
+    private String clusterNodeId;
 
     /**
      * @return event id that was used to generate this lineage
@@ -74,6 +75,18 @@ public class LineageRequestDTO {
     }
 
     /**
+     * @return id of the node in the cluster where this lineage originated
+     */
+    @ApiModelProperty(value = "The id of the node where this lineage originated if clustered.")
+    public String getClusterNodeId() {
+        return clusterNodeId;
+    }
+
+    public void setClusterNodeId(String clusterNodeId) {
+        this.clusterNodeId = clusterNodeId;
+    }
+
+    /**
      * @return uuid that was used to generate this lineage
      */
     @ApiModelProperty(

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
deleted file mode 100644
index 092e80c..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
+++ /dev/null
@@ -1,39 +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.authorization;
-
-/**
- * Represents any error that might occur while authorizing user requests.
- */
-public class AccessDeniedException extends RuntimeException {
-
-    public AccessDeniedException(Throwable cause) {
-        super(cause);
-    }
-
-    public AccessDeniedException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public AccessDeniedException(String message) {
-        super(message);
-    }
-
-    public AccessDeniedException() {
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
deleted file mode 100644
index 50f7288..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
+++ /dev/null
@@ -1,141 +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.authorization.resource;
-
-import org.apache.nifi.authorization.AccessDeniedException;
-import org.apache.nifi.authorization.AuthorizationRequest;
-import org.apache.nifi.authorization.AuthorizationResult;
-import org.apache.nifi.authorization.AuthorizationResult.Result;
-import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.RequestAction;
-import org.apache.nifi.authorization.Resource;
-import org.apache.nifi.authorization.user.NiFiUser;
-import org.apache.nifi.authorization.user.NiFiUserUtils;
-
-public interface Authorizable {
-
-    /**
-     * The parent for this Authorizable. May be null.
-     *
-     * @return the parent authorizable or null
-     */
-    Authorizable getParentAuthorizable();
-
-    /**
-     * The Resource for this Authorizable.
-     *
-     * @return the parent resource
-     */
-    Resource getResource();
-
-    /**
-     * Returns whether the current user is authorized for the specified action on the specified resource. This
-     * method does not imply the user is directly attempting to access the specified resource. If the user is
-     * attempting a direct access use Authorizable.authorize().
-     *
-     * @param authorizer authorizer
-     * @param action action
-     * @return is authorized
-     */
-    default boolean isAuthorized(Authorizer authorizer, RequestAction action) {
-        return Result.Approved.equals(checkAuthorization(authorizer, action).getResult());
-    }
-
-    /**
-     * Returns the result of an authorization request for the current user for the specified action on the specified
-     * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is
-     * attempting a direct access use Authorizable.authorize().
-     *
-     * @param authorizer authorizer
-     * @param action action
-     * @return is authorized
-     */
-    default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action) {
-        return checkAuthorization(authorizer, action, NiFiUserUtils.getNiFiUser());
-    }
-
-    /**
-     * Returns the result of an authorization request for the specified user for the specified action on the specified
-     * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is
-     * attempting a direct access use Authorizable.authorize().
-     *
-     * @param authorizer authorizer
-     * @param action action
-     * @param user user
-     * @return is authorized
-     */
-    default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user) {
-        // TODO - include user details context
-
-        // build the request
-        final AuthorizationRequest request = new AuthorizationRequest.Builder()
-                .identity(user.getIdentity())
-                .anonymous(user.isAnonymous())
-                .accessAttempt(false)
-                .action(action)
-                .resource(getResource())
-                .build();
-
-        // perform the authorization
-        final AuthorizationResult result = authorizer.authorize(request);
-
-        // verify the results
-        if (Result.ResourceNotFound.equals(result.getResult())) {
-            final Authorizable parent = getParentAuthorizable();
-            if (parent == null) {
-                return AuthorizationResult.denied();
-            } else {
-                return parent.checkAuthorization(authorizer, action);
-            }
-        } else {
-            return result;
-        }
-    }
-
-    /**
-     * Authorizes the current user for the specified action on the specified resource. This method does imply the user is
-     * directly accessing the specified resource.
-     *
-     * @param authorizer authorizer
-     * @param action action
-     */
-    default void authorize(Authorizer authorizer, RequestAction action) throws AccessDeniedException {
-        final NiFiUser user = NiFiUserUtils.getNiFiUser();
-
-        // TODO - include user details context
-
-        final AuthorizationRequest request = new AuthorizationRequest.Builder()
-            .identity(user.getIdentity())
-            .anonymous(user.isAnonymous())
-            .accessAttempt(true)
-            .action(action)
-            .resource(getResource())
-            .build();
-
-        final AuthorizationResult result = authorizer.authorize(request);
-        if (Result.ResourceNotFound.equals(result.getResult())) {
-            final Authorizable parent = getParentAuthorizable();
-            if (parent == null) {
-                throw new AccessDeniedException("Access is denied");
-            } else {
-                parent.authorize(authorizer, action);
-            }
-        } else if (Result.Denied.equals(result.getResult())) {
-            throw new AccessDeniedException(result.getExplanation());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java
new file mode 100644
index 0000000..153047e
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java
@@ -0,0 +1,41 @@
+/*
+ * 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.authorization.resource;
+
+import org.apache.nifi.authorization.Resource;
+
+public class ProvenanceEventAuthorizable implements Authorizable {
+    final Authorizable authorizable;
+
+    public ProvenanceEventAuthorizable(final Authorizable authorizable) {
+        this.authorizable = authorizable;
+    }
+
+    @Override
+    public Authorizable getParentAuthorizable() {
+        if (authorizable.getParentAuthorizable() == null) {
+            return null;
+        } else {
+            return new ProvenanceEventAuthorizable(authorizable.getParentAuthorizable());
+        }
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getProvenanceEventResource(authorizable.getResource());
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
index 5fc56af..058a1c8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
@@ -179,6 +179,18 @@ public final class ResourceFactory {
         }
     };
 
+    private final static Resource PROVENANCE_EVENT_RESOURCE = new Resource() {
+        @Override
+        public String getIdentifier() {
+            return ResourceType.ProvenanceEvent.getValue();
+        }
+
+        @Override
+        public String getName() {
+            return "Provenance Event";
+        }
+    };
+
     private final static Resource PROXY_RESOURCE = new Resource() {
         @Override
         public String getIdentifier() {
@@ -581,22 +593,19 @@ public final class ResourceFactory {
     /**
      * Gets a Resource for accessing a component's provenance events.
      *
-     * @param resourceType  The type of resource being accessed
-     * @param identifier    The identifier of the component being accessed
-     * @param name          The name of the component being accessed
-     * @return              The resource
+     * @param resource The resource for the component being accessed
+     * @return The resource for the provenance of the component being accessed
      */
-    public static Resource getComponentProvenanceResource(final ResourceType resourceType, final String identifier, final String name) {
-        final Resource componentResource = getComponentResource(resourceType, identifier, name);
+    public static Resource getProvenanceEventResource(final Resource resource) {
         return new Resource() {
             @Override
             public String getIdentifier() {
-                return String.format("%s/%s", componentResource.getIdentifier(), "provenance");
+                return String.format("%s%s", PROVENANCE_EVENT_RESOURCE.getIdentifier(), resource.getIdentifier());
             }
 
             @Override
             public String getName() {
-                return componentResource.getName() + " provenance";
+                return "Provenance Events for " + resource.getName();
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
index eb08cec..1464cab 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
@@ -30,6 +30,7 @@ public enum ResourceType {
     Processor("/processors"),
     ProcessGroup("/process-groups"),
     Provenance("/provenance"),
+    ProvenanceEvent("/provenance-events"),
     Proxy("/proxy"),
     RemoteProcessGroup("/remote-process-groups"),
     ReportingTask("/reporting-tasks"),

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
deleted file mode 100644
index f560cd7..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
+++ /dev/null
@@ -1,93 +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.authorization.user;
-
-import java.io.Serializable;
-import java.util.Objects;
-
-/**
- * An NiFiUser.
- */
-public class NiFiUser implements Serializable {
-
-    public static final NiFiUser ANONYMOUS = new NiFiUser("anonymous");
-
-    private String identity;
-    private String userName;
-
-    private NiFiUser chain;
-
-    public NiFiUser(String identity) {
-        this(identity, identity, null);
-    }
-
-    public NiFiUser(String identity, NiFiUser chain) {
-        this(identity, identity, chain);
-    }
-
-    public NiFiUser(String identity, String userName, NiFiUser chain) {
-        this.identity = identity;
-        this.userName = userName;
-        this.chain = chain;
-    }
-
-    /* getters / setters */
-
-    public String getIdentity() {
-        return identity;
-    }
-
-    public String getUserName() {
-        return userName;
-    }
-
-    public NiFiUser getChain() {
-        return chain;
-    }
-
-    public boolean isAnonymous() {
-        return this == ANONYMOUS;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final NiFiUser other = (NiFiUser) obj;
-        if (!Objects.equals(this.identity, other.identity)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 53 * hash + Objects.hashCode(this.identity);
-        return hash;
-    }
-
-    @Override
-    public String toString() {
-        return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", ");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
new file mode 100644
index 0000000..8c41a1f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
@@ -0,0 +1,94 @@
+/*
+ * 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.authorization.user;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * An implementation of NiFiUser.
+ */
+public class StandardNiFiUser implements NiFiUser, Serializable {
+    private static final long serialVersionUID = -5503790026187817496L;
+
+    public static final StandardNiFiUser ANONYMOUS = new StandardNiFiUser("anonymous");
+
+    private final String identity;
+    private final String userName;
+    private final NiFiUser chain;
+
+    public StandardNiFiUser(String identity) {
+        this(identity, identity, null);
+    }
+
+    public StandardNiFiUser(String identity, NiFiUser chain) {
+        this(identity, identity, chain);
+    }
+
+    public StandardNiFiUser(String identity, String userName, NiFiUser chain) {
+        this.identity = identity;
+        this.userName = userName;
+        this.chain = chain;
+    }
+
+
+    @Override
+    public String getIdentity() {
+        return identity;
+    }
+
+    @Override
+    public String getUserName() {
+        return userName;
+    }
+
+    @Override
+    public NiFiUser getChain() {
+        return chain;
+    }
+
+    @Override
+    public boolean isAnonymous() {
+        return this == ANONYMOUS;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (!(obj instanceof NiFiUser)) {
+            return false;
+        }
+
+        final NiFiUser other = (NiFiUser) obj;
+        return Objects.equals(this.identity, other.getIdentity());
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 53 * hash + Objects.hashCode(this.identity);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", ");
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
index b9fd0cb..e50fe39 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
@@ -30,7 +30,6 @@ import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.authorization.user.NiFiUser;
-import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.controller.label.Label;
 import org.apache.nifi.groups.ProcessGroup;
@@ -139,8 +138,8 @@ public class Template implements Authorizable {
     }
 
     @Override
-    public void authorize(final Authorizer authorizer, final RequestAction action) throws AccessDeniedException {
-        final AuthorizationResult result = checkAuthorization(authorizer, action, true);
+    public void authorize(final Authorizer authorizer, final RequestAction action, final NiFiUser user) throws AccessDeniedException {
+        final AuthorizationResult result = checkAuthorization(authorizer, action, true, user);
         if (Result.Denied.equals(result)) {
             final String explanation = result.getExplanation() == null ? "Access is denied" : result.getExplanation();
             throw new AccessDeniedException(explanation);
@@ -148,13 +147,11 @@ public class Template implements Authorizable {
     }
 
     @Override
-    public AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action) {
-        return checkAuthorization(authorizer, action, false);
+    public AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final NiFiUser user) {
+        return checkAuthorization(authorizer, action, false, user);
     }
 
-    private AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final boolean accessAttempt) {
-        final NiFiUser user = NiFiUserUtils.getNiFiUser();
-
+    private AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final boolean accessAttempt, final NiFiUser user) {
         // TODO - include user details context
 
         // build the request
@@ -172,7 +169,7 @@ public class Template implements Authorizable {
         // verify the results
         if (Result.ResourceNotFound.equals(result.getResult())) {
             for (final Authorizable child : getAuthorizableComponents()) {
-                final AuthorizationResult childResult = child.checkAuthorization(authorizer, action);
+                final AuthorizationResult childResult = child.checkAuthorization(authorizer, action, user);
                 if (Result.Denied.equals(childResult)) {
                     return childResult;
                 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
index c68c734..3d2eca2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
@@ -16,7 +16,39 @@
  */
 package org.apache.nifi.controller;
 
-import com.sun.jersey.api.client.ClientHandlerException;
+import static java.util.Objects.requireNonNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.net.ssl.SSLContext;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.action.Action;
 import org.apache.nifi.admin.service.AuditService;
@@ -29,7 +61,9 @@ import org.apache.nifi.annotation.notification.PrimaryNodeState;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.Resource;
 import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ProvenanceEventAuthorizable;
 import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.cluster.HeartbeatPayload;
 import org.apache.nifi.cluster.coordination.heartbeat.HeartbeatMonitor;
 import org.apache.nifi.cluster.coordination.node.ClusterRoles;
@@ -151,6 +185,7 @@ import org.apache.nifi.processor.StandardValidationContextFactory;
 import org.apache.nifi.provenance.ProvenanceEventRecord;
 import org.apache.nifi.provenance.ProvenanceEventRepository;
 import org.apache.nifi.provenance.ProvenanceEventType;
+import org.apache.nifi.provenance.ProvenanceAuthorizableFactory;
 import org.apache.nifi.provenance.StandardProvenanceEventRecord;
 import org.apache.nifi.remote.HttpRemoteSiteListener;
 import org.apache.nifi.remote.RemoteGroupPort;
@@ -178,6 +213,7 @@ import org.apache.nifi.stream.io.StreamUtils;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.util.ReflectionUtils;
+import org.apache.nifi.web.ResourceNotFoundException;
 import org.apache.nifi.web.api.dto.ConnectableDTO;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.ControllerServiceDTO;
@@ -198,39 +234,9 @@ import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.net.ssl.SSLContext;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.LockSupport;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import static java.util.Objects.requireNonNull;
+import com.sun.jersey.api.client.ClientHandlerException;
 
-public class FlowController implements EventAccess, ControllerServiceProvider, ReportingTaskProvider, QueueProvider, Authorizable {
+public class FlowController implements EventAccess, ControllerServiceProvider, ReportingTaskProvider, QueueProvider, Authorizable, ProvenanceAuthorizableFactory {
 
     // default repository implementations
     public static final String DEFAULT_FLOWFILE_REPO_IMPLEMENTATION = "org.apache.nifi.controller.repository.WriteAheadFlowFileRepository";
@@ -437,7 +443,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
 
         try {
             this.provenanceEventRepository = createProvenanceRepository(properties);
-            this.provenanceEventRepository.initialize(createEventReporter(bulletinRepository));
+            this.provenanceEventRepository.initialize(createEventReporter(bulletinRepository), authorizer, this);
         } catch (final Exception e) {
             throw new RuntimeException("Unable to create Provenance Repository", e);
         }
@@ -3575,17 +3581,17 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
         return null;
     }
 
-    public ProvenanceEventRecord replayFlowFile(final long provenanceEventRecordId, final String requestor) throws IOException {
-        final ProvenanceEventRecord record = provenanceEventRepository.getEvent(provenanceEventRecordId);
+    public ProvenanceEventRecord replayFlowFile(final long provenanceEventRecordId, final NiFiUser user) throws IOException {
+        final ProvenanceEventRecord record = provenanceEventRepository.getEvent(provenanceEventRecordId, user);
         if (record == null) {
             throw new IllegalStateException("Cannot find Provenance Event with ID " + provenanceEventRecordId);
         }
 
-        return replayFlowFile(record, requestor);
+        return replayFlowFile(record, user);
     }
 
     @SuppressWarnings("deprecation")
-    public ProvenanceEventRecord replayFlowFile(final ProvenanceEventRecord event, final String requestor) throws IOException {
+    public ProvenanceEventRecord replayFlowFile(final ProvenanceEventRecord event, final NiFiUser user) throws IOException {
         if (event == null) {
             throw new NullPointerException();
         }
@@ -3684,7 +3690,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
             .setFlowFileUUID(parentUUID)
             .setAttributes(Collections.<String, String> emptyMap(), flowFileRecord.getAttributes())
             .setCurrentContentClaim(event.getContentClaimContainer(), event.getContentClaimSection(), event.getContentClaimIdentifier(), event.getContentClaimOffset(), event.getFileSize())
-            .setDetails("Replay requested by " + requestor)
+            .setDetails("Replay requested by " + user.getIdentity())
             .setEventTime(System.currentTimeMillis())
             .setFlowFileEntryDate(System.currentTimeMillis())
             .setLineageStartDate(event.getLineageStartDate())
@@ -3847,6 +3853,29 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
     }
 
     @Override
+    public Authorizable createProvenanceAuthorizable(final String componentId) {
+        final String rootGroupId = getRootGroupId();
+
+        // Provenance Events are generated only by connectable components, with the exception of DOWNLOAD events,
+        // which have the root process group's identifier assigned as the component ID. So, we check if the component ID
+        // is set to the root group and otherwise assume that the ID is that of a component.
+        final ProvenanceEventAuthorizable authorizable;
+        if (rootGroupId.equals(componentId)) {
+            authorizable = new ProvenanceEventAuthorizable(rootGroup);
+        } else {
+            final Connectable connectable = rootGroup.findConnectable(componentId);
+
+            if (connectable == null) {
+                throw new ResourceNotFoundException("The component that generated this event is no longer part of the data flow.");
+            }
+
+            authorizable = new ProvenanceEventAuthorizable(connectable);
+        }
+
+        return authorizable;
+    }
+
+    @Override
     public List<Action> getFlowChanges(final int firstActionId, final int maxActions) {
         final History history = auditService.getActions(firstActionId, maxActions);
         return new ArrayList<>(history.getActions());

http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index eb8ea20..180b6bc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -2812,7 +2812,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         }
 
         // perform the authorization
-        final AuthorizationResult result = authorizable.checkAuthorization(authorizer, RequestAction.READ);
+        final AuthorizationResult result = authorizable.checkAuthorization(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
         return Result.Approved.equals(result.getResult());
     }