You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2016/11/21 20:31:19 UTC

[2/3] nifi git commit: NIFI-3050: Implemented access control logic for restricted components.

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
index 52af285..7aa8321 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
@@ -23,6 +23,7 @@ import org.apache.nifi.authorization.resource.DataAuthorizable;
 import org.apache.nifi.authorization.resource.DataTransferAuthorizable;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.authorization.resource.RestrictedComponentsAuthorizable;
 import org.apache.nifi.authorization.resource.TenantAuthorizable;
 import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.components.PropertyDescriptor;
@@ -62,6 +63,8 @@ import java.util.Set;
 class StandardAuthorizableLookup implements AuthorizableLookup {
 
     private static final TenantAuthorizable TENANT_AUTHORIZABLE = new TenantAuthorizable();
+    private static final Authorizable RESTRICTED_COMPONENTS_AUTHORIZABLE = new RestrictedComponentsAuthorizable();
+
     private static final Authorizable POLICIES_AUTHORIZABLE = new Authorizable() {
         @Override
         public Authorizable getParentAuthorizable() {
@@ -134,15 +137,20 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getProcessor(final String id) {
+    public ConfigurableComponentAuthorizable getProcessor(final String id) {
         final ProcessorNode processorNode = processorDAO.getProcessor(id);
-        return new ControllerServiceReferencingComponentAuthorizable() {
+        return new ConfigurableComponentAuthorizable() {
             @Override
             public Authorizable getAuthorizable() {
                 return processorNode;
             }
 
             @Override
+            public boolean isRestricted() {
+                return processorNode.isRestricted();
+            }
+
+            @Override
             public String getValue(PropertyDescriptor propertyDescriptor) {
                 return processorNode.getProperty(propertyDescriptor);
             }
@@ -155,16 +163,21 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getProcessorByType(String type) {
+    public ConfigurableComponentAuthorizable getProcessorByType(String type) {
         try {
             final ProcessorNode processorNode = controllerFacade.createTemporaryProcessor(type);
-            return new ControllerServiceReferencingComponentAuthorizable() {
+            return new ConfigurableComponentAuthorizable() {
                 @Override
                 public Authorizable getAuthorizable() {
                     return processorNode;
                 }
 
                 @Override
+                public boolean isRestricted() {
+                    return processorNode.isRestricted();
+                }
+
+                @Override
                 public String getValue(PropertyDescriptor propertyDescriptor) {
                     return processorNode.getProperty(propertyDescriptor);
                 }
@@ -328,15 +341,20 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getControllerService(final String id) {
+    public ConfigurableComponentAuthorizable getControllerService(final String id) {
         final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(id);
-        return new ControllerServiceReferencingComponentAuthorizable() {
+        return new ConfigurableComponentAuthorizable() {
             @Override
             public Authorizable getAuthorizable() {
                 return controllerService;
             }
 
             @Override
+            public boolean isRestricted() {
+                return controllerService.isRestricted();
+            }
+
+            @Override
             public String getValue(PropertyDescriptor propertyDescriptor) {
                 return controllerService.getProperty(propertyDescriptor);
             }
@@ -349,16 +367,21 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getControllerServiceByType(String type) {
+    public ConfigurableComponentAuthorizable getControllerServiceByType(String type) {
         try {
             final ControllerServiceNode controllerService = controllerFacade.createTemporaryControllerService(type);
-            return new ControllerServiceReferencingComponentAuthorizable() {
+            return new ConfigurableComponentAuthorizable() {
                 @Override
                 public Authorizable getAuthorizable() {
                     return controllerService;
                 }
 
                 @Override
+                public boolean isRestricted() {
+                    return controllerService.isRestricted();
+                }
+
+                @Override
                 public String getValue(PropertyDescriptor propertyDescriptor) {
                     return controllerService.getProperty(propertyDescriptor);
                 }
@@ -417,15 +440,20 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getReportingTask(final String id) {
+    public ConfigurableComponentAuthorizable getReportingTask(final String id) {
         final ReportingTaskNode reportingTaskNode = reportingTaskDAO.getReportingTask(id);
-        return new ControllerServiceReferencingComponentAuthorizable() {
+        return new ConfigurableComponentAuthorizable() {
             @Override
             public Authorizable getAuthorizable() {
                 return reportingTaskNode;
             }
 
             @Override
+            public boolean isRestricted() {
+                return reportingTaskNode.isRestricted();
+            }
+
+            @Override
             public String getValue(PropertyDescriptor propertyDescriptor) {
                 return reportingTaskNode.getProperty(propertyDescriptor);
             }
@@ -438,16 +466,21 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
-    public ControllerServiceReferencingComponentAuthorizable getReportingTaskByType(String type) {
+    public ConfigurableComponentAuthorizable getReportingTaskByType(String type) {
         try {
             final ReportingTaskNode reportingTask = controllerFacade.createTemporaryReportingTask(type);
-            return new ControllerServiceReferencingComponentAuthorizable() {
+            return new ConfigurableComponentAuthorizable() {
                 @Override
                 public Authorizable getAuthorizable() {
                     return reportingTask;
                 }
 
                 @Override
+                public boolean isRestricted() {
+                    return reportingTask.isRestricted();
+                }
+
+                @Override
                 public String getValue(PropertyDescriptor propertyDescriptor) {
                     return reportingTask.getProperty(propertyDescriptor);
                 }
@@ -603,17 +636,7 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
                 authorizable = getController();
                 break;
             case Counters:
-                authorizable = new Authorizable() {
-                    @Override
-                    public Authorizable getParentAuthorizable() {
-                        return null;
-                    }
-
-                    @Override
-                    public Resource getResource() {
-                        return ResourceFactory.getCountersResource();
-                    }
-                };
+                authorizable = getCounters();
                 break;
             case Flow:
                 authorizable = new Authorizable() {
@@ -629,17 +652,7 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
                 };
                 break;
             case Provenance:
-                authorizable = new Authorizable() {
-                    @Override
-                    public Authorizable getParentAuthorizable() {
-                        return null;
-                    }
-
-                    @Override
-                    public Resource getResource() {
-                        return ResourceFactory.getProvenanceResource();
-                    }
-                };
+                authorizable = getProvenance();
                 break;
             case Proxy:
                 authorizable = new Authorizable() {
@@ -655,7 +668,7 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
                 };
                 break;
             case Policy:
-                authorizable = POLICIES_AUTHORIZABLE;
+                authorizable = getPolicies();
                 break;
             case Resource:
                 authorizable = new Authorizable() {
@@ -671,7 +684,6 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
                 };
                 break;
             case SiteToSite:
-                // TODO - new site-to-site and port specific site-to-site
                 authorizable = new Authorizable() {
                     @Override
                     public Authorizable getParentAuthorizable() {
@@ -685,21 +697,14 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
                 };
                 break;
             case System:
-                authorizable = new Authorizable() {
-                    @Override
-                    public Authorizable getParentAuthorizable() {
-                        return null;
-                    }
-
-                    @Override
-                    public Resource getResource() {
-                        return ResourceFactory.getSystemResource();
-                    }
-                };
+                authorizable = getSystem();
                 break;
             case Tenant:
                 authorizable = getTenant();
                 break;
+            case RestrictedComponents:
+                authorizable = getRestrictedComponents();
+                break;
         }
 
         if (authorizable == null) {
@@ -721,6 +726,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
     }
 
     @Override
+    public Authorizable getRestrictedComponents() {
+        return RESTRICTED_COMPONENTS_AUTHORIZABLE;
+    }
+
+    @Override
     public Authorizable getSystem() {
         return SYSTEM_AUTHORIZABLE;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 53c0fe6..67f768a 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
@@ -2958,6 +2958,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         entity.setControllerPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getController()));
         entity.setPoliciesPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getPolicies()));
         entity.setSystemPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getSystem()));
+        entity.setRestrictedComponentsPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getRestrictedComponents()));
         return entity;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 fb38ce9..177e557 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
@@ -31,7 +31,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
 import org.apache.nifi.authorization.AuthorizationResult.Result;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.UserContextKeys;
 import org.apache.nifi.authorization.resource.Authorizable;
@@ -397,7 +397,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 // authorize the processor
-                final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getProcessor(id);
+                final ConfigurableComponentAuthorizable authorizable = lookup.getProcessor(id);
                 authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                 // authorize any referenced service
@@ -588,7 +588,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 // authorize the controller service
-                final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getControllerService(id);
+                final ConfigurableComponentAuthorizable authorizable = lookup.getControllerService(id);
                 authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                 // authorize any referenced service
@@ -753,7 +753,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
             // authorize access
             serviceFacade.authorizeAccess(lookup -> {
                 // authorize the reporting task
-                final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getReportingTask(id);
+                final ConfigurableComponentAuthorizable authorizable = lookup.getReportingTask(id);
                 authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                 // authorize any referenced service

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.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/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 09abe53..8f33ba6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -30,7 +30,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
 import org.apache.nifi.authorization.AuthorizationResult.Result;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.UserContextKeys;
 import org.apache.nifi.authorization.resource.ResourceFactory;
@@ -283,8 +283,12 @@ public class ControllerResource extends ApplicationResource {
                 lookup -> {
                     authorizeController(RequestAction.WRITE);
 
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getProcessorByType(requestReportingTask.getType());
+                    if (authorizable.isRestricted()) {
+                        lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
+                    }
+
                     if (requestReportingTask.getProperties() != null) {
-                        final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getReportingTaskByType(requestReportingTask.getType());
                         AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestReportingTask.getProperties(), authorizable, authorizer, lookup);
                     }
                 },
@@ -376,8 +380,12 @@ public class ControllerResource extends ApplicationResource {
                 lookup -> {
                     authorizeController(RequestAction.WRITE);
 
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getProcessorByType(requestControllerService.getType());
+                    if (authorizable.isRestricted()) {
+                        lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
+                    }
+
                     if (requestControllerService.getProperties() != null) {
-                        final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getControllerServiceByType(requestControllerService.getType());
                         AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup);
                     }
                 },

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 9b3805a..47a8189 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
@@ -25,7 +25,7 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -621,7 +621,7 @@ public class ControllerServiceResource extends ApplicationResource {
                 requestRevision,
                 lookup -> {
                     // authorize the service
-                    final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getControllerService(id);
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getControllerService(id);
                     authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                     // authorize any referenced services

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 527364c..c1ea58c 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
@@ -28,7 +28,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizableLookup;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.ProcessGroupAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
@@ -615,12 +615,18 @@ public class ProcessGroupResource extends ApplicationResource {
                 serviceFacade,
                 requestProcessorEntity,
                 lookup -> {
+                    final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
                     final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable();
-                    processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
+                    processGroup.authorize(authorizer, RequestAction.WRITE, user);
+
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getProcessorByType(requestProcessor.getType());
+                    if (authorizable.isRestricted()) {
+                        lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
+                    }
 
                     final ProcessorConfigDTO config = requestProcessor.getConfig();
                     if (config != null && config.getProperties() != null) {
-                        final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getProcessorByType(requestProcessor.getType());
                         AuthorizeControllerServiceReference.authorizeControllerServiceReferences(config.getProperties(), authorizable, authorizer, lookup);
                     }
                 },
@@ -2129,11 +2135,17 @@ public class ProcessGroupResource extends ApplicationResource {
                 serviceFacade,
                 requestControllerServiceEntity,
                 lookup -> {
+                    final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
                     final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable();
-                    processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
+                    processGroup.authorize(authorizer, RequestAction.WRITE, user);
+
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getProcessorByType(requestControllerService.getType());
+                    if (authorizable.isRestricted()) {
+                        lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
+                    }
 
                     if (requestControllerService.getProperties() != null) {
-                        final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getControllerServiceByType(requestControllerService.getType());
                         AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup);
                     }
                 },

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 cc16d26..fcdb99f 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
@@ -25,7 +25,7 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUser;
@@ -448,7 +448,7 @@ public class ProcessorResource extends ApplicationResource {
                 lookup -> {
                     final NiFiUser user = NiFiUserUtils.getNiFiUser();
 
-                    final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getProcessor(id);
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getProcessor(id);
                     authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, user);
 
                     final ProcessorConfigDTO config = requestProcessorDTO.getConfig();

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 4d23804..57bc51d 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
@@ -25,7 +25,7 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.ControllerServiceReferencingComponentAuthorizable;
+import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -425,7 +425,7 @@ public class ReportingTaskResource extends ApplicationResource {
                 requestRevision,
                 lookup -> {
                     // authorize reporting task
-                    final ControllerServiceReferencingComponentAuthorizable authorizable = lookup.getReportingTask(id);
+                    final ConfigurableComponentAuthorizable authorizable = lookup.getReportingTask(id);
                     authorizable.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
 
                     // authorize any referenced services

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 3383632..3f48128 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
@@ -31,6 +31,7 @@ import org.apache.nifi.action.details.FlowChangeMoveDetails;
 import org.apache.nifi.action.details.FlowChangePurgeDetails;
 import org.apache.nifi.action.details.MoveDetails;
 import org.apache.nifi.action.details.PurgeDetails;
+import org.apache.nifi.annotation.behavior.Restricted;
 import org.apache.nifi.annotation.behavior.Stateful;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
@@ -1239,6 +1240,7 @@ public final class DtoFactory {
         dto.setAnnotationData(reportingTaskNode.getAnnotationData());
         dto.setComments(reportingTaskNode.getComments());
         dto.setPersistsState(reportingTaskNode.getReportingTask().getClass().isAnnotationPresent(Stateful.class));
+        dto.setRestricted(reportingTaskNode.isRestricted());
 
         final Map<String, String> defaultSchedulingPeriod = new HashMap<>();
         defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod());
@@ -1308,6 +1310,7 @@ public final class DtoFactory {
         dto.setAnnotationData(controllerServiceNode.getAnnotationData());
         dto.setComments(controllerServiceNode.getComments());
         dto.setPersistsState(controllerServiceNode.getControllerServiceImplementation().getClass().isAnnotationPresent(Stateful.class));
+        dto.setRestricted(controllerServiceNode.isRestricted());
 
         // sort a copy of the properties
         final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
@@ -2011,6 +2014,11 @@ public final class DtoFactory {
         return dto;
     }
 
+    private String getUsageRestriction(final Class<?> cls) {
+        final Restricted restriction = cls.getAnnotation(Restricted.class);
+        return restriction == null ? null : restriction.value();
+    }
+
     /**
      * Gets the capability description from the specified class.
      */
@@ -2050,6 +2058,7 @@ public final class DtoFactory {
             final DocumentedTypeDTO type = new DocumentedTypeDTO();
             type.setType(cls.getName());
             type.setDescription(getCapabilityDescription(cls));
+            type.setUsageRestriction(getUsageRestriction(cls));
             type.setTags(getTags(cls));
             types.add(type);
         }
@@ -2075,6 +2084,7 @@ public final class DtoFactory {
         dto.setParentGroupId(node.getProcessGroup().getIdentifier());
         dto.setInputRequirement(node.getInputRequirement().name());
         dto.setPersistsState(node.getProcessor().getClass().isAnnotationPresent(Stateful.class));
+        dto.setRestricted(node.isRestricted());
 
         dto.setType(node.getCanonicalClassName());
         dto.setName(node.getName());

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/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 41eaae3..30fcbd7 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
@@ -788,6 +788,7 @@ public class ControllerFacade implements Authorizable {
         final List<Resource> resources = new ArrayList<>();
         resources.add(ResourceFactory.getFlowResource());
         resources.add(ResourceFactory.getSystemResource());
+        resources.add(ResourceFactory.getRestrictedComponentsResource());
         resources.add(ResourceFactory.getControllerResource());
         resources.add(ResourceFactory.getCountersResource());
         resources.add(ResourceFactory.getProvenanceResource());

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
index 6bd0b36..d22f418 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessControlHelper.java
@@ -43,6 +43,7 @@ public class AccessControlHelper {
     private NiFiTestUser writeUser;
     private NiFiTestUser readWriteUser;
     private NiFiTestUser noneUser;
+    private NiFiTestUser privilegedUser;
 
     private static final String CONTEXT_PATH = "/nifi-api";
 
@@ -78,6 +79,7 @@ public class AccessControlHelper {
         writeUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.WRITE_USER_DN);
         readWriteUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.READ_WRITE_USER_DN);
         noneUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.NONE_USER_DN);
+        privilegedUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.PRIVILEGED_USER_DN);
 
         // populate the initial data flow
         NiFiWebApiTest.populateFlow(server.getClient(), baseUrl, readWriteUser, READ_WRITE_CLIENT_ID);
@@ -99,6 +101,10 @@ public class AccessControlHelper {
         return noneUser;
     }
 
+    public NiFiTestUser getPrivilegedUser() {
+        return privilegedUser;
+    }
+
     public void testGenericGetUri(final String uri) throws Exception {
         ClientResponse response;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITProcessorAccessControl.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITProcessorAccessControl.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITProcessorAccessControl.java
index 37567c4..02817fc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITProcessorAccessControl.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITProcessorAccessControl.java
@@ -19,6 +19,7 @@ package org.apache.nifi.integration.accesscontrol;
 import com.sun.jersey.api.client.ClientResponse;
 import org.apache.nifi.integration.util.NiFiTestAuthorizer;
 import org.apache.nifi.integration.util.NiFiTestUser;
+import org.apache.nifi.integration.util.RestrictedProcessor;
 import org.apache.nifi.integration.util.SourceTestProcessor;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
@@ -399,6 +400,43 @@ public class ITProcessorAccessControl {
         verifyDelete(helper.getNoneUser(), NONE_CLIENT_ID, 403);
     }
 
+    /**
+     * Tests attempt to create a restricted processor.
+     *
+     * @throws Exception if there is an error creating this processor
+     */
+    @Test
+    public void testCreateRestrictedProcessor() throws Exception {
+        String url = helper.getBaseUrl() + "/process-groups/root/processors";
+
+        // create the processor
+        ProcessorDTO processor = new ProcessorDTO();
+        processor.setName("restricted");
+        processor.setType(RestrictedProcessor.class.getName());
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(READ_WRITE_CLIENT_ID);
+        revision.setVersion(0L);
+
+        // create the entity body
+        ProcessorEntity entity = new ProcessorEntity();
+        entity.setRevision(revision);
+        entity.setComponent(processor);
+
+        // perform the request as a user with read/write but no restricted access
+        ClientResponse response = helper.getReadWriteUser().testPost(url, entity);
+
+        // ensure the request is successful
+        assertEquals(403, response.getStatus());
+
+        // perform the request as a user with read/write and restricted access
+        response = helper.getPrivilegedUser().testPost(url, entity);
+
+        // ensure the request is successful
+        assertEquals(201, response.getStatus());
+    }
+
     private ProcessorEntity getRandomProcessor(final NiFiTestUser user) throws Exception {
         final String url = helper.getBaseUrl() + "/flow/process-groups/root";
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
index f5d70cf..de55b83 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java
@@ -39,6 +39,7 @@ public class NiFiTestAuthorizer implements Authorizer {
     public static final String READ_USER_DN = "read@nifi";
     public static final String WRITE_USER_DN = "write@nifi";
     public static final String READ_WRITE_USER_DN = "readwrite@nifi";
+    public static final String PRIVILEGED_USER_DN = "privileged@nifi";
 
     public static final String TOKEN_USER = "user@nifi";
 
@@ -78,15 +79,24 @@ public class NiFiTestAuthorizer implements Authorizer {
             return AuthorizationResult.approved();
         }
 
+        // restricted component access
+        if (ResourceFactory.getRestrictedComponentsResource().getIdentifier().equals(request.getResource().getIdentifier())) {
+            if (PRIVILEGED_USER_DN.equals(request.getIdentity())) {
+                return AuthorizationResult.approved();
+            } else {
+                return AuthorizationResult.denied();
+            }
+        }
+
         // read access
-        if (READ_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity())) {
+        if (READ_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) || PRIVILEGED_USER_DN.equals(request.getIdentity())) {
             if (RequestAction.READ.equals(request.getAction())) {
                 return AuthorizationResult.approved();
             }
         }
 
         // write access
-        if (WRITE_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity())) {
+        if (WRITE_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) || PRIVILEGED_USER_DN.equals(request.getIdentity())) {
             if (RequestAction.WRITE.equals(request.getAction())) {
                 return AuthorizationResult.approved();
             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/RestrictedProcessor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/RestrictedProcessor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/RestrictedProcessor.java
new file mode 100644
index 0000000..4da4b5a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/RestrictedProcessor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.integration.util;
+
+import org.apache.nifi.annotation.behavior.Restricted;
+import org.apache.nifi.processor.AbstractSessionFactoryProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSessionFactory;
+import org.apache.nifi.processor.ProcessorInitializationContext;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Restricted("")
+public class RestrictedProcessor extends AbstractSessionFactoryProcessor {
+
+    public RestrictedProcessor() {
+    }
+
+    @Override
+    public Set<Relationship> getRelationships() {
+        final Set<Relationship> rels = new HashSet<>();
+        rels.add(new Relationship.Builder().name("success").build());
+        return rels;
+    }
+
+    @Override
+    public void onTrigger(final ProcessContext context, final ProcessSessionFactory sessionFactory) throws ProcessException {
+    }
+
+    @Override
+    protected void init(final ProcessorInitializationContext context) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/common-ui.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/common-ui.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/common-ui.css
index 0466df5..cdd8318 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/common-ui.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/common-ui.css
@@ -427,7 +427,13 @@ div.button {
     cursor: pointer;
 }
 
-div.button:hover {
+div.button.disabled-button {
+    color: #a8a8a8 !important;
+    cursor: not-allowed;
+    opacity: 0.7;
+}
+
+div.button:hover:not(.disabled-button) {
     background-color: #004849;
 }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css
index e965bf2..bc198a9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/graph.css
@@ -175,6 +175,18 @@ text.processor-icon {
     font-size: 30px;
 }
 
+circle.restricted-background {
+    visibility: hidden;
+    fill: rgba(255, 255, 255, 0.90);
+}
+
+text.restricted {
+    visibility: hidden;
+    font-family: FontAwesome;
+    font-size: 12px;
+    fill: #ba554a;
+}
+
 text.run-status-icon {
     font-size: 13px;
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
index 111550c..29a3232 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/new-processor-dialog.css
@@ -86,4 +86,12 @@
 
 #processor-type-filter {
     width: 200px;
+}
+
+/*
+    Restricted
+*/
+
+div.view-usage-restriction {
+    color: #ba554a !important;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
index a1a5f89..8b90b8d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/policy-management.css
@@ -89,7 +89,7 @@ div.policy-controls {
 
 #policy-type-list {
     float: left;
-    width: 190px;
+    width: 225px;
     margin-right: 3px;
     border-left: 1px solid transparent;
     border-right: 1px solid transparent;

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/modal/jquery.modal.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/modal/jquery.modal.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/modal/jquery.modal.js
index 82f8bf6..03cca96 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/modal/jquery.modal.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/jquery/modal/jquery.modal.js
@@ -36,6 +36,7 @@
  *              hover: '#004849',
  *              text: '#ffffff'
  *          },
+ *          disabled: isDisabledFunction,
  *      handler: {
  *          click: cancelHandler
  *      }
@@ -46,6 +47,7 @@
  *              hover: '#C7D2D7',
  *              text: '#004849'
  *          },
+ *          disabled: isDisabledFunction,
  *      handler: {
  *          click: applyHandler
  *      }
@@ -101,27 +103,54 @@
     var addButtons = function (dialog, buttonModel) {
         if (isDefinedAndNotNull(buttonModel)) {
             var buttonWrapper = $('<div class="dialog-buttons"></div>');
-            var button;
             $.each(buttonModel, function (i, buttonConfig) {
-                var clazz = isDefinedAndNotNull(buttonConfig.clazz) ? buttonConfig.clazz : '';
-                if (buttonConfig.color) {
-                    button = $('<div class="button ' + clazz + '" style="color:' + buttonConfig.color.text + '; background:' + buttonConfig.color.base + ';"><span>' + buttonConfig.buttonText + '</span></div>');
-                    button.hover(function () {
-                        $(this).css("background-color", buttonConfig.color.hover);
-                    }, function () {
-                        $(this).css("background-color", buttonConfig.color.base);
+                var isDisabled = function () {
+                    return typeof buttonConfig.disabled === 'function' && buttonConfig.disabled.call() === true;
+                };
+
+                // create the button
+                var button = $('<div class="button"></div>').append($('<span></span>').text(buttonConfig.buttonText));
+
+                // add the class if specified
+                if (isDefinedAndNotNull(buttonConfig.clazz)) {
+                    button.addClass(buttonConfig.clazz);
+                }
+
+                // set the color if specified
+                if (isDefinedAndNotNull(buttonConfig.color)) {
+                    button.css({
+                        'background': buttonConfig.color.base,
+                        'color': buttonConfig.color.text
                     });
-                } else {
-                    button = $('<div class="button ' + clazz + '"><span>' + buttonConfig.buttonText + '</span></div>');
                 }
-                button.click(function () {
-                    var handler = $(this).data('handler');
-                    if (isDefinedAndNotNull(handler) && typeof handler.click === 'function') {
-                        handler.click.call(dialog);
+
+                // check if the button should be disabled
+                if (isDisabled()) {
+                    button.addClass('disabled-button');
+                } else {
+                    // enable custom hover if specified
+                    if (isDefinedAndNotNull(buttonConfig.color)) {
+                        button.hover(function () {
+                            $(this).css("background-color", buttonConfig.color.hover);
+                        }, function () {
+                            $(this).css("background-color", buttonConfig.color.base);
+                        });
                     }
-                }).data('handler', buttonConfig.handler).appendTo(buttonWrapper);
+
+                    button.click(function () {
+                        var handler = $(this).data('handler');
+                        if (isDefinedAndNotNull(handler) && typeof handler.click === 'function') {
+                            handler.click.call(dialog);
+                        }
+                    });
+                }
+
+                // add the button to the wrapper
+                button.data('handler', buttonConfig.handler).appendTo(buttonWrapper);
             });
-            buttonWrapper.appendTo(dialog);
+
+            // store the button model to refresh later
+            dialog.append(buttonWrapper).data('buttonModel', buttonModel);
         }
     };
 
@@ -259,6 +288,22 @@
         },
 
         /**
+         * Refreshes the buttons with the existing model.
+         */
+        refreshButtons: function () {
+            return this.each(function () {
+                var dialog = $(this);
+                var buttons = dialog.data('buttonModel');
+
+                // remove the current buttons
+                dialog.children('.dialog-buttons').remove();
+
+                // add the new buttons
+                addButtons(dialog, buttons);
+            });
+        },
+
+        /**
          * Sets the header text of the dialog.
          *
          * @argument {string} text Text to use a as a header

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
index b563b10..c96bab4 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/header/components/nf-ng-processor-component.js
@@ -235,6 +235,15 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
         }).fail(nf.Common.handleAjaxError);
     };
 
+    /**
+     * Whether the specified item is selectable.
+     *
+     * @param item process type
+     */
+    var isSelectable = function (item) {
+        return nf.Common.isBlank(item.usageRestriction) || nf.Common.canAccessRestrictedComponents();
+    };
+
     function ProcessorComponent() {
 
         this.icon = 'icon icon-processor';
@@ -257,7 +266,7 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
                 init: function () {
                     // initialize the processor type table
                     var processorTypesColumns = [
-                        {id: 'type', name: 'Type', field: 'label', sortable: true, resizable: true},
+                        {id: 'type', name: 'Type', field: 'label', formatter: nf.Common.typeFormatter, sortable: true, resizable: true},
                         {id: 'tags', name: 'Tags', field: 'tags', sortable: true, resizable: true}
                     ];
                     var processorTypesOptions = {
@@ -319,9 +328,15 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
                                 $('#processor-type-name').text(processorType.label).ellipsis();
                                 $('#selected-processor-name').text(processorType.label);
                                 $('#selected-processor-type').text(processorType.type);
+
+                                // refresh the buttons based on the current selection
+                                $('#new-processor-dialog').modal('refreshButtons');
                             }
                         }
                     });
+                    processorTypesGrid.onViewportChanged.subscribe(function (e, args) {
+                        nf.Common.cleanUpTooltips($('#processor-types-table'), 'div.view-usage-restriction');
+                    });
 
                     // wire up the dataview to the grid
                     processorTypesData.onRowCountChanged.subscribe(function (e, args) {
@@ -338,7 +353,31 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
                     processorTypesData.syncGridSelection(processorTypesGrid, false);
 
                     // hold onto an instance of the grid
-                    $('#processor-types-table').data('gridInstance', processorTypesGrid);
+                    $('#processor-types-table').data('gridInstance', processorTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+                        var usageRestriction = $(this).find('div.view-usage-restriction');
+                        if (usageRestriction.length && !usageRestriction.data('qtip')) {
+                            var rowId = $(this).find('span.row-id').text();
+
+                            // get the status item
+                            var item = processorTypesData.getItemById(rowId);
+
+                            // show the tooltip
+                            if (nf.Common.isDefinedAndNotNull(item.usageRestriction)) {
+                                usageRestriction.qtip($.extend({}, nf.Common.config.tooltipConfig, {
+                                    content: item.usageRestriction,
+                                    position: {
+                                        container: $('#summary'),
+                                        at: 'bottom right',
+                                        my: 'top left',
+                                        adjust: {
+                                            x: 4,
+                                            y: 4
+                                        }
+                                    }
+                                }));
+                            }
+                        }
+                    });
 
                     // load the available processor types, this select is shown in the
                     // new processor dialog when a processor is dragged onto the screen
@@ -362,6 +401,7 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
                                 label: nf.Common.substringAfterLast(type, '.'),
                                 type: type,
                                 description: nf.Common.escapeHtml(documentedType.description),
+                                usageRestriction: nf.Common.escapeHtml(documentedType.usageRestriction),
                                 tags: documentedType.tags.join(', ')
                             });
 
@@ -497,6 +537,7 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
          */
         promptForProcessorType: function (pt) {
             var self = this;
+
             // handles adding the selected processor at the specified point
             var addProcessor = function () {
                 // get the type of processor currently selected
@@ -525,10 +566,12 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
             var gridDoubleClick = function (e, args) {
                 var processorType = grid.getDataItem(args.row);
 
-                $('#selected-processor-name').text(processorType.label);
-                $('#selected-processor-type').text(processorType.type);
+                if (isSelectable(processorType)) {
+                    $('#selected-processor-name').text(processorType.label);
+                    $('#selected-processor-type').text(processorType.type);
 
-                addProcessor();
+                    addProcessor();
+                }
             };
 
             // register a handler for double click events
@@ -542,6 +585,17 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
                     hover: '#004849',
                     text: '#ffffff'
                 },
+                disabled: function () {
+                    var selected = grid.getSelectedRows();
+
+                    if (selected.length > 0) {
+                        // grid configured with multi-select = false
+                        var item = grid.getDataItem(selected[0]);
+                        return isSelectable(item) === false;
+                    } else {
+                        return false;
+                    }
+                },
                 handler: {
                     click: addProcessor
                 }
@@ -576,7 +630,15 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
             $('#processor-type-filter').focus().off('keyup').on('keyup', function (e) {
                 var code = e.keyCode ? e.keyCode : e.which;
                 if (code === $.ui.keyCode.ENTER) {
-                    addProcessor();
+                    var selected = grid.getSelectedRows();
+
+                    if (selected.length > 0) {
+                        // grid configured with multi-select = false
+                        var item = grid.getDataItem(selected[0]);
+                        if (isSelectable(item)) {
+                            addProcessor();
+                        }
+                    }
                 } else {
                     applyFilter();
                 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
index cb88182..9473978 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js
@@ -40,6 +40,15 @@ nf.ControllerServices = (function () {
     };
 
     /**
+     * Whether the specified item is selectable.
+     *
+     * @param item controller service type
+     */
+    var isSelectable = function (item) {
+        return nf.Common.isBlank(item.usageRestriction) || nf.Common.canAccessRestrictedComponents();
+    };
+
+    /**
      * Get the text out of the filter field. If the filter field doesn't
      * have any text it will contain the text 'filter list' so this method
      * accounts for that.
@@ -254,7 +263,7 @@ nf.ControllerServices = (function () {
     var initNewControllerServiceDialog = function () {
         // initialize the processor type table
         var controllerServiceTypesColumns = [
-            {id: 'type', name: 'Type', field: 'label', sortable: false, resizable: true},
+            {id: 'type', name: 'Type', field: 'label', formatter: nf.Common.typeFormatter, sortable: false, resizable: true},
             {id: 'tags', name: 'Tags', field: 'tags', sortable: false, resizable: true}
         ];
 
@@ -298,9 +307,15 @@ nf.ControllerServices = (function () {
                     $('#controller-service-type-name').text(controllerServiceType.label).ellipsis();
                     $('#selected-controller-service-name').text(controllerServiceType.label);
                     $('#selected-controller-service-type').text(controllerServiceType.type);
+
+                    // refresh the buttons based on the current selection
+                    $('#new-controller-service-dialog').modal('refreshButtons');
                 }
             }
         });
+        controllerServiceTypesGrid.onViewportChanged.subscribe(function (e, args) {
+            nf.Common.cleanUpTooltips($('#controller-service-types-table'), 'div.view-usage-restriction');
+        });
 
         // wire up the dataview to the grid
         controllerServiceTypesData.onRowCountChanged.subscribe(function (e, args) {
@@ -317,7 +332,31 @@ nf.ControllerServices = (function () {
         controllerServiceTypesData.syncGridSelection(controllerServiceTypesGrid, true);
 
         // hold onto an instance of the grid
-        $('#controller-service-types-table').data('gridInstance', controllerServiceTypesGrid);
+        $('#controller-service-types-table').data('gridInstance', controllerServiceTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+            var usageRestriction = $(this).find('div.view-usage-restriction');
+            if (usageRestriction.length && !usageRestriction.data('qtip')) {
+                var rowId = $(this).find('span.row-id').text();
+
+                // get the status item
+                var item = controllerServiceTypesData.getItemById(rowId);
+
+                // show the tooltip
+                if (nf.Common.isDefinedAndNotNull(item.usageRestriction)) {
+                    usageRestriction.qtip($.extend({}, nf.Common.config.tooltipConfig, {
+                        content: item.usageRestriction,
+                        position: {
+                            container: $('#summary'),
+                            at: 'bottom right',
+                            my: 'top left',
+                            adjust: {
+                                x: 4,
+                                y: 4
+                            }
+                        }
+                    }));
+                }
+            }
+        });
 
         // load the available controller services
         $.ajax({
@@ -339,6 +378,7 @@ nf.ControllerServices = (function () {
                     label: nf.Common.substringAfterLast(documentedType.type, '.'),
                     type: documentedType.type,
                     description: nf.Common.escapeHtml(documentedType.description),
+                    usageRestriction: nf.Common.escapeHtml(documentedType.usageRestriction),
                     tags: documentedType.tags.join(', ')
                 });
 
@@ -831,11 +871,22 @@ nf.ControllerServices = (function () {
          * @param {jQuery} serviceTable
          */
         promptNewControllerService: function (controllerServicesUri, serviceTable) {
+            // get the grid reference
+            var grid = $('#controller-service-types-table').data('gridInstance');
+
             // update the keyhandler
             $('#controller-service-type-filter').off('keyup').on('keyup', function (e) {
                 var code = e.keyCode ? e.keyCode : e.which;
                 if (code === $.ui.keyCode.ENTER) {
-                    addSelectedControllerService(controllerServicesUri, serviceTable);
+                    var selected = grid.getSelectedRows();
+
+                    if (selected.length > 0) {
+                        // grid configured with multi-select = false
+                        var item = grid.getDataItem(selected[0]);
+                        if (isSelectable(item)) {
+                            addSelectedControllerService(controllerServicesUri, serviceTable);
+                        }
+                    }
                 } else {
                     applyControllerServiceTypeFilter();
                 }
@@ -849,6 +900,17 @@ nf.ControllerServices = (function () {
                     hover: '#004849',
                     text: '#ffffff'
                 },
+                disabled: function () {
+                    var selected = grid.getSelectedRows();
+
+                    if (selected.length > 0) {
+                        // grid configured with multi-select = false
+                        var item = grid.getDataItem(selected[0]);
+                        return isSelectable(item) === false;
+                    } else {
+                        return false;
+                    }
+                },
                 handler: {
                     click: function () {
                         addSelectedControllerService(controllerServicesUri, serviceTable);
@@ -878,7 +940,10 @@ nf.ControllerServices = (function () {
             // update the dbl click handler and subsrcibe
             dblClick = function(e, args) {
                 var controllerServiceType = controllerServiceTypesGrid.getDataItem(args.row);
-                addControllerService(controllerServicesUri, serviceTable, controllerServiceType.type);
+
+                if (isSelectable(controllerServiceType)) {
+                    addControllerService(controllerServicesUri, serviceTable, controllerServiceType.type);
+                }
             };
             controllerServiceTypesGrid.onDblClick.subscribe(dblClick);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
index 19ea71e..b2f95ba 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-policy-management.js
@@ -343,6 +343,7 @@ nf.PolicyManagement = (function () {
                 nf.Common.getPolicyTypeListing('flow'),
                 nf.Common.getPolicyTypeListing('controller'),
                 nf.Common.getPolicyTypeListing('provenance'),
+                nf.Common.getPolicyTypeListing('restricted-components'),
                 nf.Common.getPolicyTypeListing('policies'),
                 nf.Common.getPolicyTypeListing('tenants'),
                 nf.Common.getPolicyTypeListing('site-to-site'),
@@ -364,7 +365,7 @@ nf.PolicyManagement = (function () {
                         $('#controller-policy-target').hide();
 
                         // record the action
-                        if (option.value === 'proxy') {
+                        if (option.value === 'proxy' || option.value === 'restricted-components') {
                             $('#selected-policy-action').text('write');
                         } else {
                             $('#selected-policy-action').text('read');
@@ -1398,7 +1399,7 @@ nf.PolicyManagement = (function () {
 
             if (policyType === 'controller') {
                 $('#selected-policy-action').text($('#controller-policy-target').combo('getSelectedOption').value);
-            } else if (policyType === 'proxy') {
+            } else if (policyType === 'proxy' || policyType === 'restricted-components') {
                 $('#selected-policy-action').text('write');
             } else {
                 $('#selected-policy-action').text('read');

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
index 9a5506a..1a02dae 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
@@ -132,6 +132,24 @@ nf.Processor = (function () {
             })
             .text('\ue807');
 
+        // restricted icon background
+        processor.append('circle')
+            .attr({
+                'r': 9,
+                'cx': 12,
+                'cy': 12,
+                'class': 'restricted-background'
+            });
+
+        // restricted icon
+        processor.append('text')
+            .attr({
+                'x': 7.75,
+                'y': 17,
+                'class': 'restricted'
+            })
+            .text('\uf132');
+
         // make processors selectable
         processor.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
     };
@@ -603,10 +621,27 @@ nf.Processor = (function () {
 
                     return color;
                 });
+
+            // restricted component indicator
+            processor.select('circle.restricted-background').style('visibility', showRestricted);
+            processor.select('text.restricted').style('visibility', showRestricted);
         });
     };
 
     /**
+     * Returns whether the resticted indicator should be shown for a given
+     * @param d
+     * @returns {*}
+     */
+    var showRestricted = function (d) {
+        if (!d.permissions.canRead) {
+            return 'hidden';
+        }
+
+        return d.component.restricted ? 'visible' : 'hidden';
+    }
+
+    /**
      * Updates the stats for the processors in the specified selection.
      *
      * @param {selection} updated           The processors to update

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
index ed70367..d41752e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js
@@ -156,6 +156,15 @@ nf.Settings = (function () {
     };
 
     /**
+     * Whether the specified item is selectable.
+     *
+     * @param item reporting task type
+     */
+    var isSelectable = function (item) {
+        return nf.Common.isBlank(item.usageRestriction) || nf.Common.canAccessRestrictedComponents();
+    };
+
+    /**
      * Formatter for the name column.
      *
      * @param {type} row
@@ -406,7 +415,17 @@ nf.Settings = (function () {
         $('#reporting-task-type-filter').on('keyup', function (e) {
             var code = e.keyCode ? e.keyCode : e.which;
             if (code === $.ui.keyCode.ENTER) {
-                addSelectedReportingTask();
+                // get the grid reference
+                var grid = $('#reporting-task-types-table').data('gridInstance');
+                var selected = grid.getSelectedRows();
+
+                if (selected.length > 0) {
+                    // grid configured with multi-select = false
+                    var item = grid.getDataItem(selected[0]);
+                    if (isSelectable(item)) {
+                        addSelectedReportingTask();
+                    }
+                }
             } else {
                 applyReportingTaskTypeFilter();
             }
@@ -414,7 +433,7 @@ nf.Settings = (function () {
 
         // initialize the processor type table
         var reportingTaskTypesColumns = [
-            {id: 'type', name: 'Type', field: 'label', sortable: false, resizable: true},
+            {id: 'type', name: 'Type', field: 'label', formatter: nf.Common.typeFormatter, sortable: false, resizable: true},
             {id: 'tags', name: 'Tags', field: 'tags', sortable: false, resizable: true}
         ];
 
@@ -458,12 +477,21 @@ nf.Settings = (function () {
                     $('#reporting-task-type-name').text(reportingTaskType.label).ellipsis();
                     $('#selected-reporting-task-name').text(reportingTaskType.label);
                     $('#selected-reporting-task-type').text(reportingTaskType.type);
+
+                    // refresh the buttons based on the current selection
+                    $('#new-reporting-task-dialog').modal('refreshButtons');
                 }
             }
         });
         reportingTaskTypesGrid.onDblClick.subscribe(function (e, args) {
             var reportingTaskType = reportingTaskTypesGrid.getDataItem(args.row);
-            addReportingTask(reportingTaskType.type);
+
+            if (isSelectable(reportingTaskType)) {
+                addReportingTask(reportingTaskType.type);
+            }
+        });
+        reportingTaskTypesGrid.onViewportChanged.subscribe(function (e, args) {
+            nf.Common.cleanUpTooltips($('#reporting-task-types-table'), 'div.view-usage-restriction');
         });
 
         // wire up the dataview to the grid
@@ -481,7 +509,31 @@ nf.Settings = (function () {
         reportingTaskTypesData.syncGridSelection(reportingTaskTypesGrid, true);
 
         // hold onto an instance of the grid
-        $('#reporting-task-types-table').data('gridInstance', reportingTaskTypesGrid);
+        $('#reporting-task-types-table').data('gridInstance', reportingTaskTypesGrid).on('mouseenter', 'div.slick-cell', function (e) {
+            var usageRestriction = $(this).find('div.view-usage-restriction');
+            if (usageRestriction.length && !usageRestriction.data('qtip')) {
+                var rowId = $(this).find('span.row-id').text();
+
+                // get the status item
+                var item = reportingTaskTypesData.getItemById(rowId);
+
+                // show the tooltip
+                if (nf.Common.isDefinedAndNotNull(item.usageRestriction)) {
+                    usageRestriction.qtip($.extend({}, nf.Common.config.tooltipConfig, {
+                        content: item.usageRestriction,
+                        position: {
+                            container: $('#summary'),
+                            at: 'bottom right',
+                            my: 'top left',
+                            adjust: {
+                                x: 4,
+                                y: 4
+                            }
+                        }
+                    }));
+                }
+            }
+        });
 
         // load the available reporting tasks
         $.ajax({
@@ -503,6 +555,7 @@ nf.Settings = (function () {
                     label: nf.Common.substringAfterLast(documentedType.type, '.'),
                     type: documentedType.type,
                     description: nf.Common.escapeHtml(documentedType.description),
+                    usageRestriction: nf.Common.escapeHtml(documentedType.usageRestriction),
                     tags: documentedType.tags.join(', ')
                 });
 
@@ -537,6 +590,17 @@ nf.Settings = (function () {
                         hover: '#004849',
                         text: '#ffffff'
                     },
+                    disabled: function () {
+                        var selected = reportingTaskTypesGrid.getSelectedRows();
+
+                        if (selected.length > 0) {
+                            // grid configured with multi-select = false
+                            var item = reportingTaskTypesGrid.getDataItem(selected[0]);
+                            return isSelectable(item) === false;
+                        } else {
+                            return false;
+                        }
+                    },
                     handler: {
                         click: function () {
                             addSelectedReportingTask();

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
index 5d7054c..b0fdb3e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js
@@ -91,6 +91,10 @@ nf.Common = (function () {
         value: 'provenance',
         description: 'Allows users to submit a Provenance Search and request Event Lineage'
     }, {
+        text: 'access restricted components',
+        value: 'restricted-components',
+        description: 'Allows users to create/modify restricted components assuming otherwise sufficient permissions'
+    }, {
         text: 'access all policies',
         value: 'policies',
         description: 'Allows users to view/modify the policies for all components'
@@ -157,6 +161,32 @@ nf.Common = (function () {
         currentUser: undefined,
 
         /**
+         * Formats type of a component for a new instance dialog.
+         *
+         * @param row
+         * @param cell
+         * @param value
+         * @param columnDef
+         * @param dataContext
+         * @returns {string}
+         */
+        typeFormatter: function (row, cell, value, columnDef, dataContext) {
+            var markup = '';
+
+            // restriction
+            if (nf.Common.isBlank(dataContext.usageRestriction) === false) {
+                markup += '<div class="view-usage-restriction fa fa-shield"></div><span class="hidden row-id">' + nf.Common.escapeHtml(dataContext.id) + '</span>';
+            } else {
+                markup += '<div class="fa"></div>';
+            }
+
+            // type
+            markup += value;
+
+            return markup;
+        },
+
+        /**
          * Sets the current user.
          * 
          * @param currentUser
@@ -272,6 +302,19 @@ nf.Common = (function () {
         },
 
         /**
+         * Determines whether the current user can access restricted comopnents.
+         *
+         * @returns {boolean}
+         */
+        canAccessRestrictedComponents: function () {
+            if (nf.Common.isDefinedAndNotNull(nf.Common.currentUser)) {
+                return nf.Common.currentUser.restrictedComponentsPermissions.canWrite === true;
+            } else {
+                return false;
+            }
+        },
+
+        /**
          * Determines whether the current user can access counters.
          * 
          * @returns {boolean}

http://git-wip-us.apache.org/repos/asf/nifi/blob/7f5eabd6/nifi-nar-bundles/nifi-hadoop-bundle/nifi-hdfs-processors/src/main/java/org/apache/nifi/processors/hadoop/DeleteHDFS.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-hadoop-bundle/nifi-hdfs-processors/src/main/java/org/apache/nifi/processors/hadoop/DeleteHDFS.java b/nifi-nar-bundles/nifi-hadoop-bundle/nifi-hdfs-processors/src/main/java/org/apache/nifi/processors/hadoop/DeleteHDFS.java
index 371b9e1..ed4d10d 100644
--- a/nifi-nar-bundles/nifi-hadoop-bundle/nifi-hdfs-processors/src/main/java/org/apache/nifi/processors/hadoop/DeleteHDFS.java
+++ b/nifi-nar-bundles/nifi-hadoop-bundle/nifi-hdfs-processors/src/main/java/org/apache/nifi/processors/hadoop/DeleteHDFS.java
@@ -16,20 +16,13 @@
  */
 package org.apache.nifi.processors.hadoop;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.Restricted;
 import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
@@ -41,16 +34,24 @@ import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @TriggerWhenEmpty
 @InputRequirement(InputRequirement.Requirement.INPUT_ALLOWED)
-@Tags({ "hadoop", "HDFS", "delete", "remove", "filesystem" })
+@Tags({ "hadoop", "HDFS", "delete", "remove", "filesystem", "restricted" })
 @CapabilityDescription("Deletes a file from HDFS. The file can be provided as an attribute from an incoming FlowFile, "
         + "or a statically set file that is periodically removed. If this processor has an incoming connection, it"
         + "will ignore running on a periodic basis and instead rely on incoming FlowFiles to trigger a delete. "
         + "Optionally, you may specify use a wildcard character to match multiple files or directories.")
+@Restricted("Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem.")
 public class DeleteHDFS extends AbstractHadoopProcessor {
     public static final Relationship REL_SUCCESS = new Relationship.Builder()
             .name("success")