http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 7e19d98..db0a568 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
@@ -23,6 +23,7 @@ import org.apache.nifi.authorization.AuthorizableLookup;
 import org.apache.nifi.authorization.AuthorizeAccess;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.ComponentAuthorizable;
 import org.apache.nifi.authorization.ProcessGroupAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.SnippetAuthorizable;
@@ -448,6 +449,16 @@ public abstract class ApplicationResource {
     }
 
     /**
+     * Authorize any restrictions for the specified ComponentAuthorizable.
+     *
+     * @param authorizer                authorizer
+     * @param authorizable              component authorizable
+     */
+    protected void authorizeRestrictions(final Authorizer authorizer, final 
ComponentAuthorizable authorizable) {
+        
authorizable.getRestrictedAuthorizables().forEach(restrictionAuthorizable -> 
restrictionAuthorizable.authorize(authorizer, RequestAction.WRITE, 
NiFiUserUtils.getNiFiUser()));
+    }
+
+    /**
      * Authorizes the specified process group.
      *
      * @param processGroupAuthorizable    process group

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 c5c40be..004b5d2 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
@@ -46,8 +46,8 @@ import org.apache.nifi.web.api.entity.ControllerServiceEntity;
 import org.apache.nifi.web.api.entity.Entity;
 import org.apache.nifi.web.api.entity.HistoryEntity;
 import org.apache.nifi.web.api.entity.NodeEntity;
-import org.apache.nifi.web.api.entity.RegistryClientsEntity;
 import org.apache.nifi.web.api.entity.RegistryClientEntity;
+import org.apache.nifi.web.api.entity.RegistryClientsEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.DateTimeParameter;
@@ -277,7 +277,7 @@ public class ControllerResource extends ApplicationResource 
{
                         authorizable = 
lookup.getConfigurableComponent(requestReportingTask.getType(), 
requestReportingTask.getBundle());
 
                         if (authorizable.isRestricted()) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
NiFiUserUtils.getNiFiUser());
+                            authorizeRestrictions(authorizer, authorizable);
                         }
 
                         if (requestReportingTask.getProperties() != null) {
@@ -775,7 +775,7 @@ public class ControllerResource extends ApplicationResource 
{
                         authorizable = 
lookup.getConfigurableComponent(requestControllerService.getType(), 
requestControllerService.getBundle());
 
                         if (authorizable.isRestricted()) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
NiFiUserUtils.getNiFiUser());
+                            authorizeRestrictions(authorizer, authorizable);
                         }
 
                         if (requestControllerService.getProperties() != null) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 7c93220..ce266da 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
@@ -159,7 +159,6 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -1894,7 +1893,7 @@ public class ProcessGroupResource extends 
ApplicationResource {
                         authorizable = 
lookup.getConfigurableComponent(requestProcessor.getType(), 
requestProcessor.getBundle());
 
                         if (authorizable.isRestricted()) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
user);
+                            authorizeRestrictions(authorizer, authorizable);
                         }
 
                         final ProcessorConfigDTO config = 
requestProcessor.getConfig();
@@ -3037,11 +3036,9 @@ public class ProcessGroupResource extends 
ApplicationResource {
                     final NiFiUser user = NiFiUserUtils.getNiFiUser();
                     final SnippetAuthorizable snippet = 
authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), 
false);
 
-                    // flag to only perform the restricted check once, atomic 
reference so we can mark final and use in lambda
-                    final AtomicBoolean restrictedCheckPerformed = new 
AtomicBoolean(false);
                     final Consumer<ComponentAuthorizable> authorizeRestricted 
= authorizable -> {
-                        if (authorizable.isRestricted() && 
restrictedCheckPerformed.compareAndSet(false, true)) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
user);
+                        if (authorizable.isRestricted()) {
+                            authorizeRestrictions(authorizer, authorizable);
                         }
                     };
 
@@ -3213,11 +3210,9 @@ public class ProcessGroupResource extends 
ApplicationResource {
                     // ensure read on the template
                     final TemplateContentsAuthorizable templateContents = 
lookup.getTemplateContents(requestInstantiateTemplateRequestEntity.getSnippet());
 
-                    // flag to only perform the restricted check once, atomic 
reference so we can mark final and use in lambda
-                    final AtomicBoolean restrictedCheckPerformed = new 
AtomicBoolean(false);
                     final Consumer<ComponentAuthorizable> authorizeRestricted 
= authorizable -> {
-                        if (authorizable.isRestricted() && 
restrictedCheckPerformed.compareAndSet(false, true)) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
user);
+                        if (authorizable.isRestricted()) {
+                            authorizeRestrictions(authorizer, authorizable);
                         }
                     };
 
@@ -3595,7 +3590,7 @@ public class ProcessGroupResource extends 
ApplicationResource {
                         authorizable = 
lookup.getConfigurableComponent(requestControllerService.getType(), 
requestControllerService.getBundle());
 
                         if (authorizable.isRestricted()) {
-                            
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, 
user);
+                            authorizeRestrictions(authorizer, authorizable);
                         }
 
                         if (requestControllerService.getProperties() != null) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 359b524..4306d0d 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
@@ -34,6 +34,7 @@ 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.Restriction;
 import org.apache.nifi.annotation.behavior.Stateful;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.DeprecationNotice;
@@ -2408,9 +2409,47 @@ public final class DtoFactory {
         return dto;
     }
 
+    private boolean isRestricted(final Class<?> cls) {
+        return cls.isAnnotationPresent(Restricted.class);
+    }
+
     private String getUsageRestriction(final Class<?> cls) {
-        final Restricted restriction = cls.getAnnotation(Restricted.class);
-        return restriction == null ? null : restriction.value();
+        final Restricted restricted = cls.getAnnotation(Restricted.class);
+
+        if (restricted == null) {
+            return null;
+        }
+
+        if (StringUtils.isBlank(restricted.value())) {
+            return null;
+        }
+
+        return restricted.value();
+    }
+
+    private Set<ExplicitRestrictionDTO> getExplicitRestrictions(final Class<?> 
cls) {
+        final Restricted restricted = cls.getAnnotation(Restricted.class);
+
+        if (restricted == null) {
+            return null;
+        }
+
+        final Restriction[] restrictions = restricted.restrictions();
+
+        if (restrictions == null || restrictions.length == 0) {
+            return null;
+        }
+
+        return Arrays.stream(restrictions).map(restriction -> {
+            final RequiredPermissionDTO requiredPermission = new 
RequiredPermissionDTO();
+            
requiredPermission.setId(restriction.requiredPermission().getPermissionIdentifier());
+            
requiredPermission.setLabel(restriction.requiredPermission().getPermissionLabel());
+
+            final ExplicitRestrictionDTO usageRestriction = new 
ExplicitRestrictionDTO();
+            usageRestriction.setRequiredPermission(requiredPermission);
+            usageRestriction.setExplanation(restriction.explanation());
+            return usageRestriction;
+        }).collect(Collectors.toSet());
     }
 
     private String getDeprecationReason(final Class<?> cls) {
@@ -2649,7 +2688,9 @@ public final class DtoFactory {
             dto.setBundle(createBundleDto(coordinate));
             dto.setControllerServiceApis(createControllerServiceApiDto(cls));
             dto.setDescription(getCapabilityDescription(cls));
+            dto.setRestricted(isRestricted(cls));
             dto.setUsageRestriction(getUsageRestriction(cls));
+            dto.setExplicitRestrictions(getExplicitRestrictions(cls));
             dto.setDeprecationReason(getDeprecationReason(cls));
             dto.setTags(getTags(cls));
             types.add(dto);

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 72702a6..1463468 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
@@ -33,6 +33,7 @@ import org.apache.nifi.bundle.Bundle;
 import org.apache.nifi.bundle.BundleCoordinate;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.components.ConfigurableComponent;
+import org.apache.nifi.components.RequiredPermission;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Port;
@@ -110,6 +111,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -808,7 +810,6 @@ 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());
@@ -818,6 +819,10 @@ public class ControllerFacade implements Authorizable {
         resources.add(ResourceFactory.getResourceResource());
         resources.add(ResourceFactory.getSiteToSiteResource());
 
+        // restricted components
+        resources.add(ResourceFactory.getRestrictedComponentsResource());
+        Arrays.stream(RequiredPermission.values()).forEach(requiredPermission 
-> 
resources.add(ResourceFactory.getRestrictedComponentsResource(requiredPermission)));
+
         final ProcessGroup root = 
flowController.getGroup(flowController.getRootGroupId());
 
         // include the root group

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 a7293b2..279da21 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
@@ -46,6 +46,7 @@ public class AccessControlHelper {
     private NiFiTestUser readWriteUser;
     private NiFiTestUser noneUser;
     private NiFiTestUser privilegedUser;
+    private NiFiTestUser executeCodeUser;
 
     private static final String CONTEXT_PATH = "/nifi-api";
 
@@ -83,6 +84,7 @@ public class AccessControlHelper {
         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);
+        executeCodeUser = new NiFiTestUser(server.getClient(), 
NiFiTestAuthorizer.EXECUTED_CODE_USER_DN);
 
         // populate the initial data flow
         NiFiWebApiTest.populateFlow(server.getClient(), baseUrl, 
readWriteUser, READ_WRITE_CLIENT_ID);
@@ -108,6 +110,10 @@ public class AccessControlHelper {
         return privilegedUser;
     }
 
+    public NiFiTestUser getExecuteCodeUser() {
+        return executeCodeUser;
+    }
+
     public void testGenericGetUri(final String uri) throws Exception {
         Response response;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 2b70930..a42d169 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
@@ -16,6 +16,7 @@
  */
 package org.apache.nifi.integration.accesscontrol;
 
+import org.apache.nifi.integration.util.ExecuteCodeRestrictedProcessor;
 import org.apache.nifi.integration.util.NiFiTestAuthorizer;
 import org.apache.nifi.integration.util.NiFiTestUser;
 import org.apache.nifi.integration.util.RestrictedProcessor;
@@ -439,6 +440,12 @@ public class ITProcessorAccessControl {
         // ensure the request is successful
         assertEquals(403, response.getStatus());
 
+        // perform the request as a user with read/write and only execute code 
restricted access
+        response = helper.getExecuteCodeUser().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);
 
@@ -448,7 +455,54 @@ public class ITProcessorAccessControl {
         final ProcessorEntity responseEntity = 
response.readEntity(ProcessorEntity.class);
 
         // remove the restricted component
-        deleteRestrictedComponent(responseEntity);
+        deleteRestrictedComponent(responseEntity, helper.getPrivilegedUser());
+    }
+
+    /**
+     * Tests attempt to create a restricted processor requiring execute code 
permissions.
+     *
+     * @throws Exception if there is an error creating this processor
+     */
+    @Test
+    public void testCreateExecuteCodeRestrictedProcessor() throws Exception {
+        createExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
+        createExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
+    }
+
+    private void createExecuteCodeRestrictedProcessor(final NiFiTestUser user) 
throws Exception {
+        String url = helper.getBaseUrl() + "/process-groups/root/processors";
+
+        // create the processor
+        ProcessorDTO processor = new ProcessorDTO();
+        processor.setName("execute code restricted");
+        processor.setType(ExecuteCodeRestrictedProcessor.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
+        Response 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 = user.testPost(url, entity);
+
+        // ensure the request is successful
+        assertEquals(201, response.getStatus());
+
+        final ProcessorEntity responseEntity = 
response.readEntity(ProcessorEntity.class);
+
+        // remove the restricted component
+        deleteRestrictedComponent(responseEntity, user);
     }
 
     /**
@@ -459,7 +513,7 @@ public class ITProcessorAccessControl {
     @Test
     public void testCopyPasteRestrictedProcessor() throws Exception {
         final String copyUrl = helper.getBaseUrl() + 
"/process-groups/root/snippet-instance";
-        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent();
+        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent(RestrictedProcessor.class.getName(), 
helper.getPrivilegedUser());
         final SnippetEntity snippetEntity = tuple.getValue();
 
         // build the copy/paste request
@@ -474,6 +528,12 @@ public class ITProcessorAccessControl {
         // ensure the request failed... need privileged users since snippet 
comprised of the restricted components
         assertEquals(403, response.getStatus());
 
+        // perform the request as a user with read/write and only execute code 
restricted access
+        response = helper.getExecuteCodeUser().testPost(copyUrl, copyRequest);
+
+        // ensure the request is successful
+        assertEquals(403, response.getStatus());
+
         // create the snippet
         response = helper.getPrivilegedUser().testPost(copyUrl, copyRequest);
 
@@ -483,8 +543,49 @@ public class ITProcessorAccessControl {
         final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
 
         // remove the restricted processors
-        deleteRestrictedComponent(tuple.getKey());
-        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
+        deleteRestrictedComponent(tuple.getKey(), helper.getPrivilegedUser());
+        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null),
 helper.getPrivilegedUser());
+    }
+
+    /**
+     * Tests attempting to copy/paste a restricted processor requiring execute 
code permissions.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testCopyPasteExecuteCodeRestrictedProcessor() throws Exception 
{
+        copyPasteExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
+        copyPasteExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
+    }
+
+    private void copyPasteExecuteCodeRestrictedProcessor(final NiFiTestUser 
user) throws Exception {
+        final String copyUrl = helper.getBaseUrl() + 
"/process-groups/root/snippet-instance";
+        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent(ExecuteCodeRestrictedProcessor.class.getName(),
 user);
+        final SnippetEntity snippetEntity = tuple.getValue();
+
+        // build the copy/paste request
+        final CopySnippetRequestEntity copyRequest = new 
CopySnippetRequestEntity();
+        copyRequest.setSnippetId(snippetEntity.getSnippet().getId());
+        copyRequest.setOriginX(0.0);
+        copyRequest.setOriginY(0.0);
+
+        // create the snippet
+        Response response = helper.getReadWriteUser().testPost(copyUrl, 
copyRequest);
+
+        // ensure the request failed... need privileged users since snippet 
comprised of the restricted components
+        assertEquals(403, response.getStatus());
+
+        // perform the request as a user with read/write and only execute code 
restricted access
+        response = user.testPost(copyUrl, copyRequest);
+
+        // ensure the request is successful
+        assertEquals(201, response.getStatus());
+
+        final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
+
+        // remove the restricted processors
+        deleteRestrictedComponent(tuple.getKey(), user);
+        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null),
 user);
     }
 
     /**
@@ -496,7 +597,7 @@ public class ITProcessorAccessControl {
     public void testTemplateWithRestrictedProcessor() throws Exception {
         final String createTemplateUrl = helper.getBaseUrl() + 
"/process-groups/root/templates";
         final String instantiateTemplateUrl = helper.getBaseUrl() + 
"/process-groups/root/template-instance";
-        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent();
+        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent(RestrictedProcessor.class.getName(), 
helper.getPrivilegedUser());
         final SnippetEntity snippetEntity = tuple.getValue();
 
         // create the template
@@ -512,7 +613,7 @@ public class ITProcessorAccessControl {
 
         response = helper.getReadWriteUser().testPost(createTemplateUrl, 
createTemplateRequest);
 
-        // ensure the request is successfull
+        // ensure the request is successful
         assertEquals(201, response.getStatus());
 
         final TemplateEntity templateEntity = 
response.readEntity(TemplateEntity.class);
@@ -530,6 +631,12 @@ public class ITProcessorAccessControl {
         assertEquals(403, response.getStatus());
 
         // create the snippet
+        response = 
helper.getExecuteCodeUser().testPost(instantiateTemplateUrl, 
instantiateTemplateRequest);
+
+        // ensure the request failed... need privileged user since the 
template is comprised of restricted components
+        assertEquals(403, response.getStatus());
+
+        // create the snippet
         response = helper.getPrivilegedUser().testPost(instantiateTemplateUrl, 
instantiateTemplateRequest);
 
         // ensure the request is successful
@@ -539,18 +646,79 @@ public class ITProcessorAccessControl {
 
         // clean up the resources created during this test
         deleteTemplate(templateEntity);
-        deleteRestrictedComponent(tuple.getKey());
-        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
+        deleteRestrictedComponent(tuple.getKey(), helper.getPrivilegedUser());
+        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null),
 helper.getPrivilegedUser());
+    }
+
+    /**
+     * Tests attempting to use a template with a restricted processor 
requiring execute code permissions.
+     *
+     * @throws Exception ex
+     */
+    @Test
+    public void testTemplateWithExecuteCodeRestrictedProcessor() throws 
Exception {
+        templateWithExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
+        
templateWithExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
+    }
+
+    private void templateWithExecuteCodeRestrictedProcessor(final NiFiTestUser 
user) throws Exception {
+        final String createTemplateUrl = helper.getBaseUrl() + 
"/process-groups/root/templates";
+        final String instantiateTemplateUrl = helper.getBaseUrl() + 
"/process-groups/root/template-instance";
+        final Tuple<ProcessorEntity, SnippetEntity> tuple = 
createSnippetWithRestrictedComponent(ExecuteCodeRestrictedProcessor.class.getName(),
 helper.getPrivilegedUser());
+        final SnippetEntity snippetEntity = tuple.getValue();
+
+        // create the template
+        final CreateTemplateRequestEntity createTemplateRequest = new 
CreateTemplateRequestEntity();
+        createTemplateRequest.setSnippetId(snippetEntity.getSnippet().getId());
+        createTemplateRequest.setName("test");
+
+        // create the snippet
+        Response response = helper.getWriteUser().testPost(createTemplateUrl, 
createTemplateRequest);
+
+        // ensure the request failed... need read perms to the components in 
the snippet
+        assertEquals(403, response.getStatus());
+
+        response = helper.getReadWriteUser().testPost(createTemplateUrl, 
createTemplateRequest);
+
+        // ensure the request is successful
+        assertEquals(201, response.getStatus());
+
+        final TemplateEntity templateEntity = 
response.readEntity(TemplateEntity.class);
+
+        // build the template request
+        final InstantiateTemplateRequestEntity instantiateTemplateRequest = 
new InstantiateTemplateRequestEntity();
+        
instantiateTemplateRequest.setTemplateId(templateEntity.getTemplate().getId());
+        instantiateTemplateRequest.setOriginX(0.0);
+        instantiateTemplateRequest.setOriginY(0.0);
+
+        // create the snippet
+        response = helper.getReadWriteUser().testPost(instantiateTemplateUrl, 
instantiateTemplateRequest);
+
+        // ensure the request failed... need privileged user since the 
template is comprised of restricted components
+        assertEquals(403, response.getStatus());
+
+        // create the snippet
+        response = user.testPost(instantiateTemplateUrl, 
instantiateTemplateRequest);
+
+        // ensure the request is successful
+        assertEquals(201, response.getStatus());
+
+        final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
+
+        // clean up the resources created during this test
+        deleteTemplate(templateEntity);
+        deleteRestrictedComponent(tuple.getKey(), user);
+        
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null),
 user);
     }
 
-    private Tuple<ProcessorEntity, SnippetEntity> 
createSnippetWithRestrictedComponent() throws Exception {
+    private Tuple<ProcessorEntity, SnippetEntity> 
createSnippetWithRestrictedComponent(final String restrictedClassName, final 
NiFiTestUser user) throws Exception {
         final String processorUrl = helper.getBaseUrl() + 
"/process-groups/root/processors";
         final String snippetUrl = helper.getBaseUrl() + "/snippets";
 
         // create the processor
         ProcessorDTO processor = new ProcessorDTO();
         processor.setName("restricted");
-        processor.setType(RestrictedProcessor.class.getName());
+        processor.setType(restrictedClassName);
 
         // create the revision
         final RevisionDTO revision = new RevisionDTO();
@@ -563,7 +731,7 @@ public class ITProcessorAccessControl {
         entity.setComponent(processor);
 
         // perform the request as a user with read/write and restricted access
-        Response response = helper.getPrivilegedUser().testPost(processorUrl, 
entity);
+        Response response = user.testPost(processorUrl, entity);
 
         // ensure the request is successful
         assertEquals(201, response.getStatus());
@@ -604,7 +772,7 @@ public class ITProcessorAccessControl {
         assertEquals(200, response.getStatus());
     }
 
-    private void deleteRestrictedComponent(final ProcessorEntity entity) 
throws Exception {
+    private void deleteRestrictedComponent(final ProcessorEntity entity, final 
NiFiTestUser user) throws Exception {
         if (entity == null) {
             Assert.fail("Failed to get Processor from template or snippet 
request.");
             return;
@@ -621,7 +789,7 @@ public class ITProcessorAccessControl {
         // ensure the request fails... needs access to restricted components
         assertEquals(403, response.getStatus());
 
-        response = helper.getPrivilegedUser().testDelete(entity.getUri(), 
queryParams);
+        response = user.testDelete(entity.getUri(), queryParams);
 
         // ensure the request is successful
         assertEquals(200, response.getStatus());

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/ExecuteCodeRestrictedProcessor.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/ExecuteCodeRestrictedProcessor.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/ExecuteCodeRestrictedProcessor.java
new file mode 100644
index 0000000..c1e951d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/ExecuteCodeRestrictedProcessor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.annotation.behavior.Restriction;
+import org.apache.nifi.components.RequiredPermission;
+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(
+    restrictions = {
+        @Restriction(
+                requiredPermission = RequiredPermission.EXECUTE_CODE,
+                explanation = "specifically executes code")
+    }
+)
+public class ExecuteCodeRestrictedProcessor extends 
AbstractSessionFactoryProcessor {
+
+    public ExecuteCodeRestrictedProcessor() {
+    }
+
+    @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/b1217f52/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 c72d512..dba618e 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
@@ -25,6 +25,7 @@ import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.exception.AuthorizationAccessException;
 import org.apache.nifi.authorization.exception.AuthorizerCreationException;
 import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.components.RequiredPermission;
 
 /**
  * Contains extra rules to convenience when in component based access control 
tests.
@@ -40,6 +41,7 @@ public class NiFiTestAuthorizer implements Authorizer {
     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 EXECUTED_CODE_USER_DN = "executecode@nifi";
 
     public static final String TOKEN_USER = "user@nifi";
 
@@ -88,15 +90,28 @@ public class NiFiTestAuthorizer implements Authorizer {
             }
         }
 
+        // execute code access
+        if 
(ResourceFactory.getRestrictedComponentsResource(RequiredPermission.EXECUTE_CODE).getIdentifier().equals(request.getResource().getIdentifier()))
 {
+            if (EXECUTED_CODE_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()) || 
PRIVILEGED_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()) || 
EXECUTED_CODE_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()) || 
PRIVILEGED_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()) || 
EXECUTED_CODE_USER_DN.equals(request.getIdentity())) {
+
             if (RequestAction.WRITE.equals(request.getAction())) {
                 return AuthorizationResult.approved();
             }

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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
index 4da4b5a..2b793f6 100644
--- 
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
@@ -27,7 +27,9 @@ import org.apache.nifi.processor.exception.ProcessException;
 import java.util.HashSet;
 import java.util.Set;
 
-@Restricted("")
+@Restricted(
+    value = "generally restricted"
+)
 public class RestrictedProcessor extends AbstractSessionFactoryProcessor {
 
     public RestrictedProcessor() {

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
index 366dc4f..e6ab191 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
@@ -14,4 +14,5 @@
 # limitations under the License.
 org.apache.nifi.integration.util.SourceTestProcessor
 org.apache.nifi.integration.util.TerminationTestProcessor
-org.apache.nifi.integration.util.RestrictedProcessor
\ No newline at end of file
+org.apache.nifi.integration.util.RestrictedProcessor
+org.apache.nifi.integration.util.ExecuteCodeRestrictedProcessor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
index 7cd08e0..946c53d 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/policy-management.jsp
@@ -30,6 +30,7 @@
         <div id="global-policy-controls" class="hidden policy-controls">
             <div id="policy-type-list"></div>
             <div id="controller-policy-target" class="hidden"></div>
+            <div id="restricted-component-required-permissions" 
class="hidden"></div>
             <div class="clear"></div>
         </div>
         <div id="component-policy-controls" class="hidden policy-controls">
@@ -90,6 +91,7 @@
         </div>
         <div id="policy-loading-container" class="loading-container"></div>
         <div id="admin-policy-message" class="hidden">Only listing component 
specific administrators. Inherited administrators not shown.</div>
+        <div id="restriction-message" class="hidden">Only listing restriction 
specific users. Users with permission "regardless of restrictions" not shown 
but are also allowed.</div>
         <div class="clear"></div>
     </div>
 </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 667291d..90777fa 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 {
     float: left;
 }
 
-#policy-type-list {
+#policy-type-list, #restricted-component-required-permissions {
     float: left;
     width: 225px;
     margin-right: 3px;
@@ -275,7 +275,7 @@ div.remove-allowed-entity {
     admin policy message
 */
 
-#admin-policy-message {
+#admin-policy-message, #restriction-message {
     float: right;
     margin-top: 8px;
     color: #775351;

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 55adc4d..c111dcf 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
@@ -288,7 +288,7 @@
          * @param item process type
          */
         var isSelectable = function (item) {
-            return nfCommon.isBlank(item.usageRestriction) || 
nfCommon.canAccessRestrictedComponents();
+            return item.restricted === false || 
nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
         };
 
         function ProcessorComponent() {
@@ -436,9 +436,28 @@
                                 var item = 
processorTypesData.getItemById(rowId);
 
                                 // show the tooltip
-                                if 
(nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
+                                if (item.restricted === true) {
+                                    var restrictionTip = $('<div></div>');
+
+                                    if 
(nfCommon.isBlank(item.usageRestriction)) {
+                                        restrictionTip.append($('<p 
style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
+                                    } else {
+                                        restrictionTip.append($('<p 
style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the 
following permissions:'));
+                                    }
+
+                                    var restrictions = [];
+                                    if 
(nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+                                        $.each(item.explicitRestrictions, 
function (_, explicitRestriction) {
+                                            var requiredPermission = 
explicitRestriction.requiredPermission;
+                                            restrictions.push("'" + 
requiredPermission.label + "' - " + 
nfCommon.escapeHtml(explicitRestriction.explanation));
+                                        });
+                                    } else {
+                                        restrictions.push('Access to 
restricted components regardless of restrictions.');
+                                    }
+                                    
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
                                     usageRestriction.qtip($.extend({}, 
nfCommon.config.tooltipConfig, {
-                                        content: item.usageRestriction,
+                                        content: restrictionTip,
                                         position: {
                                             container: $('#summary'),
                                             at: 'bottom right',
@@ -453,6 +472,8 @@
                             }
                         });
 
+                        var generalRestriction = 
nfCommon.getPolicyTypeListing('restricted-components');
+
                         // load the available processor types, this select is 
shown in the
                         // new processor dialog when a processor is dragged 
onto the screen
                         $.ajax({
@@ -462,6 +483,8 @@
                         }).done(function (response) {
                             var tags = [];
                             var groups = d3.set();
+                            var restrictedUsage = d3.map();
+                            var requiredPermissions = d3.map();
 
                             // begin the update
                             processorTypesData.beginUpdate();
@@ -470,6 +493,46 @@
                             $.each(response.processorTypes, function (i, 
documentedType) {
                                 var type = documentedType.type;
 
+                                if (documentedType.restricted === true) {
+                                    if 
(nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+                                        
$.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
+                                            var requiredPermission = 
explicitRestriction.requiredPermission;
+
+                                            // update required permissions
+                                            if 
(!requiredPermissions.has(requiredPermission.id)) {
+                                                
requiredPermissions.set(requiredPermission.id, requiredPermission.label);
+                                            }
+
+                                            // update component restrictions
+                                            if 
(!restrictedUsage.has(requiredPermission.id)) {
+                                                
restrictedUsage.set(requiredPermission.id, []);
+                                            }
+
+                                            
restrictedUsage.get(requiredPermission.id).push({
+                                                type: 
nfCommon.formatType(documentedType),
+                                                bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                                                explanation: 
nfCommon.escapeHtml(explicitRestriction.explanation)
+                                            })
+                                        });
+                                    } else {
+                                        // update required permissions
+                                        if 
(!requiredPermissions.has(generalRestriction.value)) {
+                                            
requiredPermissions.set(generalRestriction.value, generalRestriction.text);
+                                        }
+
+                                        // update component restrictions
+                                        if 
(!restrictedUsage.has(generalRestriction.value)) {
+                                            
restrictedUsage.set(generalRestriction.value, []);
+                                        }
+
+                                        
restrictedUsage.get(generalRestriction.value).push({
+                                            type: 
nfCommon.formatType(documentedType),
+                                            bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                                            explanation: 
nfCommon.escapeHtml(documentedType.usageRestriction)
+                                        });
+                                    }
+                                }
+
                                 // record the group
                                 groups.add(documentedType.bundle.group);
 
@@ -480,7 +543,9 @@
                                     type: type,
                                     bundle: documentedType.bundle,
                                     description: 
nfCommon.escapeHtml(documentedType.description),
+                                    restricted:  documentedType.restricted,
                                     usageRestriction: 
nfCommon.escapeHtml(documentedType.usageRestriction),
+                                    explicitRestrictions: 
documentedType.explicitRestrictions,
                                     tags: documentedType.tags.join(', ')
                                 });
 
@@ -497,6 +562,9 @@
                             processorTypesData.reSort();
                             processorTypesGrid.invalidate();
 
+                            // set the component restrictions and the 
corresponding required permissions
+                            
nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
+
                             // set the total number of processors
                             $('#total-processor-types, 
#displayed-processor-types').text(response.processorTypes.length);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
index 9347bd4..7a8cf65 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
@@ -56,6 +56,9 @@
     var nfBirdseye;
     var nfGraph;
 
+    var restrictedUsage = d3.map();
+    var requiredPermissions = d3.map();
+
     var config = {
         storage: {
             namePrefix: 'nifi-view-'
@@ -1843,6 +1846,41 @@
         },
 
         /**
+         * Adds the restricted usage and the required permissions.
+         *
+         * @param additionalRestrictedUsages
+         * @param additionalRequiredPermissions
+         */
+        addComponentRestrictions: function (additionalRestrictedUsages, 
additionalRequiredPermissions) {
+            additionalRestrictedUsages.each(function (componentRestrictions, 
requiredPermissionId) {
+                if (!restrictedUsage.has(requiredPermissionId)) {
+                    restrictedUsage.set(requiredPermissionId, []);
+                }
+
+                componentRestrictions.forEach(function (componentRestriction) {
+                    
restrictedUsage.get(requiredPermissionId).push(componentRestriction);
+                });
+            });
+            additionalRequiredPermissions.each(function 
(requiredPermissionLabel, requiredPermissionId) {
+                if (!requiredPermissions.has(requiredPermissionId)) {
+                    requiredPermissions.set(requiredPermissionId, 
requiredPermissionLabel);
+                }
+            });
+        },
+
+        /**
+         * Gets the component restrictions and the require permissions.
+         *
+         * @returns {{restrictedUsage: map, requiredPermissions: map}} 
component restrictions
+         */
+        getComponentRestrictions: function () {
+            return {
+                restrictedUsage: restrictedUsage,
+                requiredPermissions: requiredPermissions
+            };
+        },
+
+        /**
          * Set the group id.
          *
          * @argument {string} gi       The group id

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 0a604a9..9797a47 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
@@ -106,7 +106,7 @@
      * @param item controller service type
      */
     var isSelectable = function (item) {
-        return nfCommon.isBlank(item.usageRestriction) || 
nfCommon.canAccessRestrictedComponents();
+        return item.restricted === false || 
nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
     };
 
     /**
@@ -462,9 +462,28 @@
                 var item = controllerServiceTypesData.getItemById(rowId);
 
                 // show the tooltip
-                if (nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
+                if (item.restricted === true) {
+                    var restrictionTip = $('<div></div>');
+
+                    if (nfCommon.isBlank(item.usageRestriction)) {
+                        restrictionTip.append($('<p style="margin-bottom: 
3px;"></p>').text('Requires the following permissions:'));
+                    } else {
+                        restrictionTip.append($('<p style="margin-bottom: 
3px;"></p>').text(item.usageRestriction + ' Requires the following 
permissions:'));
+                    }
+
+                    var restrictions = [];
+                    if 
(nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+                        $.each(item.explicitRestrictions, function (_, 
explicitRestriction) {
+                            var requiredPermission = 
explicitRestriction.requiredPermission;
+                            restrictions.push("'" + requiredPermission.label + 
"' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
+                        });
+                    } else {
+                        restrictions.push('Access to restricted components 
regardless of restrictions.');
+                    }
+                    
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
                     usageRestriction.qtip($.extend({}, 
nfCommon.config.tooltipConfig, {
-                        content: item.usageRestriction,
+                        content: restrictionTip,
                         position: {
                             container: $('#summary'),
                             at: 'bottom right',
@@ -508,6 +527,8 @@
             }
         });
 
+        var generalRestriction = 
nfCommon.getPolicyTypeListing('restricted-components');
+
         // load the available controller services
         $.ajax({
             type: 'GET',
@@ -517,12 +538,54 @@
             var id = 0;
             var tags = [];
             var groups = d3.set();
+            var restrictedUsage = d3.map();
+            var requiredPermissions = d3.map();
 
             // begin the update
             controllerServiceTypesData.beginUpdate();
 
             // go through each controller service type
             $.each(response.controllerServiceTypes, function (i, 
documentedType) {
+                if (documentedType.restricted === true) {
+                    if 
(nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+                        $.each(documentedType.explicitRestrictions, function 
(_, explicitRestriction) {
+                            var requiredPermission = 
explicitRestriction.requiredPermission;
+
+                            // update required permissions
+                            if 
(!requiredPermissions.has(requiredPermission.id)) {
+                                requiredPermissions.set(requiredPermission.id, 
requiredPermission.label);
+                            }
+
+                            // update component restrictions
+                            if (!restrictedUsage.has(requiredPermission.id)) {
+                                restrictedUsage.set(requiredPermission.id, []);
+                            }
+
+                            restrictedUsage.get(requiredPermission.id).push({
+                                type: nfCommon.formatType(documentedType),
+                                bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                                explanation: explicitRestriction.explanation
+                            })
+                        });
+                    } else {
+                        // update required permissions
+                        if 
(!requiredPermissions.has(generalRestriction.value)) {
+                            requiredPermissions.set(generalRestriction.value, 
generalRestriction.text);
+                        }
+
+                        // update component restrictions
+                        if (!restrictedUsage.has(generalRestriction.value)) {
+                            restrictedUsage.set(generalRestriction.value, []);
+                        }
+
+                        restrictedUsage.get(generalRestriction.value).push({
+                            type: nfCommon.formatType(documentedType),
+                            bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                            explanation: documentedType.usageRestriction
+                        });
+                    }
+                }
+
                 // record the group
                 groups.add(documentedType.bundle.group);
 
@@ -534,7 +597,9 @@
                     bundle: documentedType.bundle,
                     controllerServiceApis: 
documentedType.controllerServiceApis,
                     description: 
nfCommon.escapeHtml(documentedType.description),
+                    restricted:  documentedType.restricted,
                     usageRestriction: 
nfCommon.escapeHtml(documentedType.usageRestriction),
+                    explicitRestrictions: documentedType.explicitRestrictions,
                     tags: documentedType.tags.join(', ')
                 });
 
@@ -551,6 +616,9 @@
             controllerServiceTypesData.reSort();
             controllerServiceTypesGrid.invalidate();
 
+            // set the component restrictions and the corresponding required 
permissions
+            nfCanvasUtils.addComponentRestrictions(restrictedUsage, 
requiredPermissions);
+
             // set the total number of processors
             $('#total-controller-service-types, 
#displayed-controller-service-types').text(response.controllerServiceTypes.length);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 99830e4..c0da481 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
@@ -64,6 +64,7 @@
     };
 
     var initialized = false;
+    var initializedComponentRestrictions = false;
 
     var initAddTenantToPolicyDialog = function () {
         $('#new-policy-user-button').on('click', function () {
@@ -418,7 +419,10 @@
 
                     // if the option is for a specific component
                     if (globalPolicySupportsReadWrite(option.value)) {
-                        // update the policy target and let it relaod the 
policy
+                        $('#restricted-component-required-permissions').hide();
+                        $('#restriction-message').hide();
+
+                        // update the policy target and let it reload the 
policy
                         
$('#controller-policy-target').combo('setSelectedOption', {
                             'value': 'read'
                         }).show();
@@ -432,6 +436,59 @@
                             $('#selected-policy-action').text('read');
                         }
 
+                        // handle any granular restrictions
+                        if (option.value === 'restricted-components') {
+                            if (!initializedComponentRestrictions) {
+                                var regardlessOfRestrictions = 'regardless of 
restrictions';
+                                var componentRestrictions = 
nfCanvasUtils.getComponentRestrictions();
+                                var requiredPermissions = 
componentRestrictions.requiredPermissions;
+
+                                var options = [{
+                                    text: regardlessOfRestrictions,
+                                    value: '',
+                                    description: 'Allows users to 
create/modify all restricted components regardless of restrictions.'
+                                }];
+
+                                requiredPermissions.each(function (label, id) {
+                                    if (id !== option.value) {
+                                        options.push({
+                                            text: "requiring '" + label + "'",
+                                            value: id,
+                                            description: "Allows users to 
create/modify restricted components requiring '" + nfCommon.escapeHtml(label) + 
"'"
+                                        });
+                                    }
+                                });
+
+                                options.sort(function (a, b) {
+                                    if (a.text === regardlessOfRestrictions) {
+                                        return -1;
+                                    } else if (b.text === 
regardlessOfRestrictions) {
+                                        return 1;
+                                    }
+
+                                    return a.text < b.text ? -1 : a.text > 
b.text ? 1 : 0;
+                                });
+
+                                
$('#restricted-component-required-permissions').combo({
+                                    options: options,
+                                    select: function (restrictionOption) {
+                                        if (restrictionOption.text === 
regardlessOfRestrictions) {
+                                            $('#restriction-message').hide();
+                                        } else {
+                                            $('#restriction-message').show();
+                                        }
+
+                                        loadPolicy();
+                                    }
+                                });
+                            }
+
+                            
$('#restricted-component-required-permissions').show();
+                        } else {
+                            $('#restriction-message').hide();
+                            
$('#restricted-component-required-permissions').hide();
+                        }
+
                         // reload the policy
                         loadPolicy();
                     }
@@ -766,6 +823,14 @@
             resource += ('/' + componentId);
         }
 
+        // identify more granular restrict component access if applicable
+        if (resource === 'restricted-components') {
+            var requiredPermission = 
$('#restricted-component-required-permissions').combo('getSelectedOption').value;
+            if (!nfCommon.isBlank(requiredPermission)) {
+                resource += ('/' + requiredPermission);
+            }
+        }
+
         return {
             'action': $('#selected-policy-action').text(),
             'resource': '/' + resource
@@ -909,7 +974,10 @@
 
         var policyDeferred;
         if (resourceAndAction.resource.startsWith('/policies')) {
-            $('#admin-policy-message').show();
+            // if this is a component specific policy permission, show the 
admin policy message
+            if (resourceAndAction.resource.endsWith('/policies')) {
+                $('#admin-policy-message').show();
+            }
 
             policyDeferred = $.Deferred(function (deferred) {
                 $.ajax({
@@ -985,6 +1053,87 @@
                     }
                 });
             }).promise();
+        } else if 
(resourceAndAction.resource.startsWith('/restricted-components')) {
+            $('#admin-policy-message').hide();
+
+            policyDeferred = $.Deferred(function (deferred) {
+                $.ajax({
+                    type: 'GET',
+                    url: '../nifi-api/policies/' + resourceAndAction.action + 
resourceAndAction.resource,
+                    dataType: 'json'
+                }).done(function (policyEntity) {
+                    // update the refresh timestamp
+                    $('#policy-last-refreshed').text(policyEntity.generated);
+
+                    // ensure appropriate actions for the loaded policy
+                    if (policyEntity.permissions.canRead === true) {
+                        var policy = policyEntity.component;
+
+                        // if the return policy is for the desired policy (not 
inherited, show it)
+                        if (resourceAndAction.resource === policy.resource) {
+                            // populate the policy details
+                            populatePolicy(policyEntity);
+                        } else {
+                            // reset the policy
+                            resetPolicy();
+
+                            // show an appropriate message
+                            $('#policy-message').text('No restriction specific 
users.');
+
+                            if (nfCanvasUtils.isConfigurableAuthorizer()) {
+                                // we don't know if the user has permissions 
to the desired policy... show create button and allow the server to decide
+                                $('#new-policy-message').show();
+                            }
+                        }
+                    } else {
+                        // reset the policy
+                        resetPolicy();
+
+                        // show an appropriate message
+                        $('#policy-message').text('Not authorized to view the 
policy.');
+
+                        if (nfCanvasUtils.isConfigurableAuthorizer()) {
+                            // we don't know if the user has permissions to 
the desired policy... show create button and allow the server to decide
+                            $('#new-policy-message').show();
+                        }
+                    }
+
+                    deferred.resolve();
+                }).fail(function (xhr, status, error) {
+                    if (xhr.status === 404) {
+                        // reset the policy
+                        resetPolicy();
+
+                        // show an appropriate message
+                        if (resourceAndAction.resource === 
'/restricted-components') {
+                            $('#policy-message').text('No users with 
permission "regardless of restrictions."');
+                        } else {
+                            $('#policy-message').text('No users with 
permission to specific restriction.');
+                        }
+
+                        if (nfCanvasUtils.isConfigurableAuthorizer()) {
+                            // we don't know if the user has permissions to 
the desired policy... show create button and allow the server to decide
+                            $('#new-policy-message').show();
+                        }
+
+                        deferred.resolve();
+                    } else if (xhr.status === 403) {
+                        // reset the policy
+                        resetPolicy();
+
+                        // show an appropriate message
+                        $('#policy-message').text('Not authorized to access 
the policy for the specified resource.');
+
+                        deferred.resolve();
+                    } else {
+                        // reset the policy
+                        resetPolicy();
+
+                        deferred.reject();
+                        nfErrorHandler.handleAjaxError(xhr, status, error);
+                    }
+                });
+            }).promise();
         } else {
             $('#admin-policy-message').hide();
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 824312a..563aff3 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
@@ -218,7 +218,7 @@
      * @param item reporting task type
      */
     var isSelectable = function (item) {
-        return nfCommon.isBlank(item.usageRestriction) || 
nfCommon.canAccessRestrictedComponents();
+        return item.restricted === false || 
nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
     };
 
     /**
@@ -682,9 +682,28 @@
                 var item = reportingTaskTypesData.getItemById(rowId);
 
                 // show the tooltip
-                if (nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
+                if (item.restricted === true) {
+                    var restrictionTip = $('<div></div>');
+
+                    if (nfCommon.isBlank(item.usageRestriction)) {
+                        restrictionTip.append($('<p style="margin-bottom: 
3px;"></p>').text('Requires the following permissions:'));
+                    } else {
+                        restrictionTip.append($('<p style="margin-bottom: 
3px;"></p>').text(item.usageRestriction + ' Requires the following 
permissions:'));
+                    }
+
+                    var restrictions = [];
+                    if 
(nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
+                        $.each(item.explicitRestrictions, function (_, 
explicitRestriction) {
+                            var requiredPermission = 
explicitRestriction.requiredPermission;
+                            restrictions.push("'" + requiredPermission.label + 
"' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
+                        });
+                    } else {
+                        restrictions.push('Access to restricted components 
regardless of restrictions.');
+                    }
+                    
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
+
                     usageRestriction.qtip($.extend({}, 
nfCommon.config.tooltipConfig, {
-                        content: item.usageRestriction,
+                        content: restrictionTip,
                         position: {
                             container: $('#summary'),
                             at: 'bottom right',
@@ -699,6 +718,8 @@
             }
         });
 
+        var generalRestriction = 
nfCommon.getPolicyTypeListing('restricted-components');
+
         // load the available reporting tasks
         $.ajax({
             type: 'GET',
@@ -708,12 +729,54 @@
             var id = 0;
             var tags = [];
             var groups = d3.set();
+            var restrictedUsage = d3.map();
+            var requiredPermissions = d3.map();
 
             // begin the update
             reportingTaskTypesData.beginUpdate();
 
             // go through each reporting task type
             $.each(response.reportingTaskTypes, function (i, documentedType) {
+                if (documentedType.restricted === true) {
+                    if 
(nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
+                        $.each(documentedType.explicitRestrictions, function 
(_, explicitRestriction) {
+                            var requiredPermission = 
explicitRestriction.requiredPermission;
+
+                            // update required permissions
+                            if 
(!requiredPermissions.has(requiredPermission.id)) {
+                                requiredPermissions.set(requiredPermission.id, 
requiredPermission.label);
+                            }
+
+                            // update component restrictions
+                            if (!restrictedUsage.has(requiredPermission.id)) {
+                                restrictedUsage.set(requiredPermission.id, []);
+                            }
+
+                            restrictedUsage.get(requiredPermission.id).push({
+                                type: nfCommon.formatType(documentedType),
+                                bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                                explanation: 
nfCommon.escapeHtml(explicitRestriction.explanation)
+                            })
+                        });
+                    } else {
+                        // update required permissions
+                        if 
(!requiredPermissions.has(generalRestriction.value)) {
+                            requiredPermissions.set(generalRestriction.value, 
generalRestriction.text);
+                        }
+
+                        // update component restrictions
+                        if (!restrictedUsage.has(generalRestriction.value)) {
+                            restrictedUsage.set(generalRestriction.value, []);
+                        }
+
+                        restrictedUsage.get(generalRestriction.value).push({
+                            type: nfCommon.formatType(documentedType),
+                            bundle: 
nfCommon.formatBundle(documentedType.bundle),
+                            explanation: 
nfCommon.escapeHtml(documentedType.usageRestriction)
+                        });
+                    }
+                }
+
                 // record the group
                 groups.add(documentedType.bundle.group);
 
@@ -724,7 +787,9 @@
                     type: documentedType.type,
                     bundle: documentedType.bundle,
                     description: 
nfCommon.escapeHtml(documentedType.description),
+                    restricted:  documentedType.restricted,
                     usageRestriction: 
nfCommon.escapeHtml(documentedType.usageRestriction),
+                    explicitRestrictions: documentedType.explicitRestrictions,
                     tags: documentedType.tags.join(', ')
                 });
 
@@ -741,6 +806,9 @@
             reportingTaskTypesData.reSort();
             reportingTaskTypesGrid.invalidate();
 
+            // set the component restrictions and the corresponding required 
permissions
+            nfCanvasUtils.addComponentRestrictions(restrictedUsage, 
requiredPermissions);
+
             // set the total number of processors
             $('#total-reporting-task-types, 
#displayed-reporting-task-types').text(response.reportingTaskTypes.length);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/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 f89c4aa..42f0deb 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
@@ -119,7 +119,7 @@
     }, {
         text: 'access restricted components',
         value: 'restricted-components',
-        description: 'Allows users to create/modify restricted components 
assuming otherwise sufficient permissions'
+        description: 'Allows users to create/modify restricted components 
assuming other permissions are sufficient'
     }, {
         text: 'access all policies',
         value: 'policies',
@@ -315,7 +315,7 @@
             var markup = '';
 
             // restriction
-            if (nfCommon.isBlank(dataContext.usageRestriction) === false) {
+            if (dataContext.restricted === true) {
                 markup += '<div class="view-usage-restriction fa 
fa-shield"></div><span class="hidden row-id">' + 
nfCommon.escapeHtml(dataContext.id) + '</span>';
             } else {
                 markup += '<div class="fa"></div>';
@@ -590,7 +590,7 @@
         },
 
         /**
-         * Determines whether the current user can access restricted 
comopnents.
+         * Determines whether the current user can access restricted 
components.
          *
          * @returns {boolean}
          */
@@ -603,6 +603,56 @@
         },
 
         /**
+         * Determines whether the current user can access the specific 
explicit component restrictions.
+         *
+         * @param {object} explicitRestrictions
+         * @returns {boolean}
+         */
+        canAccessComponentRestrictions: function (explicitRestrictions) {
+            if (nfCommon.isDefinedAndNotNull(nfCommon.currentUser)) {
+                if 
(nfCommon.currentUser.restrictedComponentsPermissions.canWrite === true) {
+                    return true;
+                }
+
+                var satisfiesRequiredPermission = function 
(requiredPermission) {
+                    if 
(nfCommon.isEmpty(nfCommon.currentUser.componentRestrictionPermissions)) {
+                        return false;
+                    }
+
+                    var hasPermission = false;
+
+                    
$.each(nfCommon.currentUser.componentRestrictionPermissions, function (_, 
componentRestrictionPermission) {
+                        if 
(componentRestrictionPermission.requiredPermission.id === 
requiredPermission.id) {
+                            if 
(componentRestrictionPermission.permissions.canWrite === true) {
+                                hasPermission = true;
+                                return false;
+                            }
+                        }
+                    });
+
+                    return hasPermission;
+                };
+
+                var satisfiesRequiredPermissions = true;
+
+                if (nfCommon.isEmpty(explicitRestrictions)) {
+                    satisfiesRequiredPermissions = false;
+                } else {
+                    $.each(explicitRestrictions, function (_, 
explicitRestriction) {
+                        if 
(!satisfiesRequiredPermission(explicitRestriction.requiredPermission)) {
+                            satisfiesRequiredPermissions = false;
+                            return false;
+                        }
+                    });
+                }
+
+                return satisfiesRequiredPermissions;
+            } else {
+                return false;
+            }
+        },
+
+        /**
          * Determines whether the current user can access counters.
          *
          * @returns {boolean}

http://git-wip-us.apache.org/repos/asf/nifi/blob/b1217f52/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users-table.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users-table.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users-table.js
index 6c55dd8..6da6668 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users-table.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users-table.js
@@ -517,7 +517,7 @@
     };
 
     /**
-     * Generates a human readable global policy strung.
+     * Generates a human readable global policy string.
      *
      * @param dataContext
      * @returns {string}
@@ -528,6 +528,23 @@
     };
 
     /**
+     * Generates a human readable restricted component policy string.
+     *
+     * @param dataContext
+     * @returns {string}
+     */
+    var restrictedComponentResourceParser = function (dataContext) {
+        var resource = dataContext.component.resource;
+
+        if (resource === '/restricted-components') {
+            return 'Restricted components regardless of restrictions';
+        }
+
+        var subResource = nfCommon.substringAfterFirst(resource, 
'/restricted-components/');
+        return "Restricted components requiring '" + subResource + "'";
+    };
+
+    /**
      * Generates a human readable component policy string.
      *
      * @param dataContext
@@ -591,12 +608,7 @@
         var policyDisplayNameFormatter = function (row, cell, value, 
columnDef, dataContext) {
             // if the user has permission to the policy
             if (dataContext.permissions.canRead === true) {
-                // check if Global policy
-                if 
(nfCommon.isUndefinedOrNull(dataContext.component.componentReference)) {
-                    return globalResourceParser(dataContext);
-                }
-                // not a global policy... check if user has access to the 
component reference
-                return componentResourceParser(dataContext);
+                return formatPolicy(dataContext);
             } else {
                 return '<span class="unset">' + 
nfCommon.escapeHtml(dataContext.id) + '</span>';
             }
@@ -943,6 +955,25 @@
     };
 
     /**
+     * Formats the specified policy.
+     *
+     * @param dataContext
+     * @returns {string}
+     */
+    var formatPolicy = function (dataContext) {
+        if 
(dataContext.component.resource.startsWith('/restricted-components')) {
+            // restricted components policy
+            return restrictedComponentResourceParser(dataContext);
+        } else if 
(nfCommon.isUndefinedOrNull(dataContext.component.componentReference)) {
+            // global policy
+            return globalResourceParser(dataContext);
+        } else {
+            // not restricted/global policy... check if user has access to the 
component reference
+            return componentResourceParser(dataContext);
+        }
+    };
+
+    /**
      * Sorts the specified data using the specified sort details.
      *
      * @param {object} sortDetails
@@ -962,26 +993,14 @@
 
                     // if the user has permission to the policy
                     if (a.permissions.canRead === true) {
-                        // check if Global policy
-                        if 
(nfCommon.isUndefinedOrNull(a.component.componentReference)) {
-                            aString = globalResourceParser(a);
-                        } else {
-                            // not a global policy... check if user has access 
to the component reference
-                            aString = componentResourceParser(a);
-                        }
+                        aString = formatPolicy(a);
                     } else {
                         aString = a.id;
                     }
 
                     // if the user has permission to the policy
                     if (b.permissions.canRead === true) {
-                        // check if Global policy
-                        if 
(nfCommon.isUndefinedOrNull(b.component.componentReference)) {
-                            bString = globalResourceParser(b);
-                        } else {
-                            // not a global policy... check if user has access 
to the component reference
-                            bString = componentResourceParser(b);
-                        }
+                        bString = formatPolicy(b);
                     } else {
                         bString = b.id;
                     }

Reply via email to