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

[4/4] nifi git commit: NIFI-375: Added operation policy

NIFI-375: Added operation policy

The operation policy allows that a user to operate components even if they does not have direct READ/WRITE
permission of the component.

Following operations are controlled by the new operate policy:
- Start/stop/enable/disable Processors, ControllerServices,
ReportingTasks, Input/OuputPorts
- Enable/disable transmission of RemoteInput/OutputPorts and
RemoteProcessGroups
- Terminate Processor threads

Refactored what API exposes

The previous commit let API exposes few fields in DTO. But we should
avoid returning partial DTO as it complicates authorization logic.

Instead, this commit adds StatusDTO for ReportingTaskEntity and
ControllerServiceEntity, so that it can be returned regardless of having
READ permission. Component DTO can only be returned with a READ
permission.

Refactor RPG same as ControllerService.

WIP incorporating review comments.

Incorporated review comments

- Cleaned up merger classes
- Recreate DTO instance at each function during two phase commmit

Restrict enabling ControllerService without read permission

Revert the last commit.

Fix review comments.

- Renamed confusing static method names and its parameters
- Removed unnecessary permission checks from UI condition

Fixed delete action display condition.

Fixed NPE at Summary.

Apply operation policy to activateControllerServices.

Removed OperationPermissible from ComponentEntity.

This closes #2990


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

Branch: refs/heads/master
Commit: f570cb980ddbb8292044ba3ff30304ed157dc839
Parents: 9161b17
Author: Koji Kawamura <ij...@apache.org>
Authored: Fri Aug 24 17:58:25 2018 +0900
Committer: Matt Gilman <ma...@gmail.com>
Committed: Wed Sep 19 15:28:41 2018 -0400

----------------------------------------------------------------------
 .../src/main/asciidoc/administration-guide.adoc |   4 +
 .../nifi-framework/nifi-authorizer/pom.xml      |   8 +
 .../MockPolicyBasedAuthorizer.java              | 196 -------------
 .../nifi/web/api/dto/ControllerServiceDTO.java  |   2 +-
 ...ontrollerServiceReferencingComponentDTO.java |   2 +-
 .../web/api/dto/status/ComponentStatusDTO.java  |  82 ++++++
 .../dto/status/ControllerServiceStatusDTO.java  |  37 +++
 .../dto/status/RemoteProcessGroupStatusDTO.java |  14 +
 .../api/dto/status/ReportingTaskStatusDTO.java  |  37 +++
 .../api/entity/ComponentRunStatusEntity.java    |  86 ++++++
 .../web/api/entity/ControllerServiceEntity.java |  54 +++-
 ...rollerServiceReferencingComponentEntity.java |  20 +-
 .../ControllerServiceRunStatusEntity.java       |  48 ++++
 .../web/api/entity/OperationPermissible.java    |  32 +++
 .../apache/nifi/web/api/entity/PortEntity.java  |  20 +-
 .../web/api/entity/PortRunStatusEntity.java     |  48 ++++
 .../nifi/web/api/entity/ProcessorEntity.java    |  20 +-
 .../api/entity/ProcessorRunStatusEntity.java    |  48 ++++
 .../api/entity/RemotePortRunStatusEntity.java   |  48 ++++
 .../api/entity/RemoteProcessGroupEntity.java    |  21 +-
 .../entity/RemoteProcessGroupPortEntity.java    |  20 +-
 .../web/api/entity/ReportingTaskEntity.java     |  39 ++-
 .../entity/ReportingTaskRunStatusEntity.java    |  48 ++++
 .../nifi-framework-authorization/pom.xml        |   6 +
 .../resource/OperationAuthorizable.java         |  85 ++++++
 .../authorization/resource/ResourceFactory.java |  27 ++
 .../authorization/resource/ResourceType.java    |  21 +-
 .../resource/OperationAuthorizableTest.java     | 226 +++++++++++++++
 .../cluster/manager/ComponentEntityMerger.java  |   6 +
 .../manager/ControllerServiceEntityMerger.java  |  29 +-
 .../cluster/manager/PermissionsDtoMerger.java   |   3 +
 .../nifi/cluster/manager/StatusMerger.java      |   1 +
 .../ControllerServiceEntityMergerSpec.groovy    |  94 +++++--
 .../RemoteProcessGroupEntityMergerTest.java     |  16 +-
 .../nifi-framework/nifi-framework-core/pom.xml  |   6 +
 .../MockPolicyBasedAuthorizer.java              | 183 ------------
 .../nifi-framework/nifi-mock-authorizer/pom.xml |  31 ++
 .../MockPolicyBasedAuthorizer.java              | 196 +++++++++++++
 .../StandardAuthorizableLookup.java             |  81 +++---
 .../nifi/web/StandardNiFiServiceFacade.java     |  97 ++++---
 .../nifi/web/api/ControllerServiceResource.java |  91 +++++-
 .../org/apache/nifi/web/api/FlowResource.java   |  21 +-
 .../apache/nifi/web/api/InputPortResource.java  |  90 ++++++
 .../apache/nifi/web/api/OutputPortResource.java |  91 ++++++
 .../apache/nifi/web/api/ProcessorResource.java  |  93 +++++-
 .../web/api/RemoteProcessGroupResource.java     | 282 +++++++++++++++++++
 .../nifi/web/api/ReportingTaskResource.java     |  90 ++++++
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  43 ++-
 .../apache/nifi/web/api/dto/EntityFactory.java  |  44 ++-
 .../nifi/web/controller/ControllerFacade.java   |   7 +
 .../StandardAuthorizableLookupTest.java         |  69 +++++
 .../src/main/webapp/js/nf/canvas/nf-actions.js  |  42 +--
 .../main/webapp/js/nf/canvas/nf-canvas-utils.js |  29 +-
 .../main/webapp/js/nf/canvas/nf-context-menu.js |   6 +-
 .../js/nf/canvas/nf-controller-service.js       | 144 ++++++----
 .../js/nf/canvas/nf-controller-services.js      | 135 +++++----
 .../webapp/js/nf/canvas/nf-policy-management.js |   7 +
 .../nf/canvas/nf-remote-process-group-ports.js  |  68 +++--
 .../js/nf/canvas/nf-remote-process-group.js     |  33 +--
 .../webapp/js/nf/canvas/nf-reporting-task.js    |  12 +-
 .../src/main/webapp/js/nf/canvas/nf-settings.js |  59 ++--
 .../src/main/webapp/js/nf/nf-common.js          |  10 +
 .../main/webapp/js/nf/users/nf-users-table.js   |   3 +
 .../nifi-framework/pom.xml                      |   1 +
 64 files changed, 2709 insertions(+), 803 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-docs/src/main/asciidoc/administration-guide.adoc
----------------------------------------------------------------------
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index d67a3e1..18702fb 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -1538,6 +1538,10 @@ Component level access policies govern the following component level authorizati
 |Allows users to modify component configuration details
 |`resource="/<component-type>/<component-UUID>" action="W"`
 
+|operate the component
+|Allows users to operate components by changing component run status (start/stop/enable/disable), remote port transmission status, or terminating processor threads
+|`resource="/operation/<component-type>/<component-UUID>" action="W"`
+
 |view provenance
 |Allows users to view provenance events generated by this component
 |`resource="/provenance-data/<component-type>/<component-UUID>" action="R"`

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml
index 0d4467a..feb2a15 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml
@@ -96,6 +96,14 @@
             <artifactId>nifi-properties-loader</artifactId>
         </dependency>
 
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-mock-authorizer</artifactId>
+            <version>1.8.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+
         <!-- Spock testing dependencies-->
         <dependency>
             <groupId>org.spockframework</groupId>

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/MockPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/MockPolicyBasedAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/MockPolicyBasedAuthorizer.java
deleted file mode 100644
index b2a9662..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/test/java/org/apache/nifi/authorization/MockPolicyBasedAuthorizer.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.authorization;
-
-import org.apache.nifi.authorization.exception.AuthorizationAccessException;
-import org.apache.nifi.authorization.exception.AuthorizerCreationException;
-import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Mock implementation of AbstractPolicyBasedAuthorizer.
- */
-public class MockPolicyBasedAuthorizer extends AbstractPolicyBasedAuthorizer implements AuthorizationAuditor {
-
-    private Set<Group> groups = new HashSet<>();
-    private Set<User> users = new HashSet<>();
-    private Set<AccessPolicy> policies = new HashSet<>();
-
-    private Set<AuthorizationRequest> audited = new HashSet();
-
-    public MockPolicyBasedAuthorizer() {
-
-    }
-
-    public MockPolicyBasedAuthorizer(Set<Group> groups, Set<User> users, Set<AccessPolicy> policies) {
-        if (groups != null) {
-            this.groups.addAll(groups);
-        }
-        if (users != null) {
-            this.users.addAll(users);
-        }
-        if (policies != null) {
-            this.policies.addAll(policies);
-        }
-    }
-
-    @Override
-    public Group doAddGroup(Group group) throws AuthorizationAccessException {
-        groups.add(group);
-        return group;
-    }
-
-    @Override
-    public Group getGroup(String identifier) throws AuthorizationAccessException {
-        return groups.stream().filter(g -> g.getIdentifier().equals(identifier)).findFirst().get();
-    }
-
-    @Override
-    public Group doUpdateGroup(Group group) throws AuthorizationAccessException {
-        deleteGroup(group);
-        return addGroup(group);
-    }
-
-    @Override
-    public Group deleteGroup(Group group) throws AuthorizationAccessException {
-        groups.remove(group);
-        return group;
-    }
-
-    @Override
-    public Set<Group> getGroups() throws AuthorizationAccessException {
-        return groups;
-    }
-
-    @Override
-    public User doAddUser(User user) throws AuthorizationAccessException {
-        users.add(user);
-        return user;
-    }
-
-    @Override
-    public User getUser(String identifier) throws AuthorizationAccessException {
-        return users.stream().filter(u -> u.getIdentifier().equals(identifier)).findFirst().get();
-    }
-
-    @Override
-    public User getUserByIdentity(String identity) throws AuthorizationAccessException {
-        return users.stream().filter(u -> u.getIdentity().equals(identity)).findFirst().get();
-    }
-
-    @Override
-    public User doUpdateUser(User user) throws AuthorizationAccessException {
-        deleteUser(user);
-        return addUser(user);
-    }
-
-    @Override
-    public User deleteUser(User user) throws AuthorizationAccessException {
-        users.remove(user);
-        return user;
-    }
-
-    @Override
-    public Set<User> getUsers() throws AuthorizationAccessException {
-        return users;
-    }
-
-    @Override
-    protected AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
-        policies.add(accessPolicy);
-        return accessPolicy;
-    }
-
-    @Override
-    public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
-        return policies.stream().filter(p -> p.getIdentifier().equals(identifier)).findFirst().get();
-    }
-
-    @Override
-    public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
-        deleteAccessPolicy(accessPolicy);
-        return addAccessPolicy(accessPolicy);
-    }
-
-    @Override
-    public AccessPolicy deleteAccessPolicy(AccessPolicy policy) throws AuthorizationAccessException {
-        policies.remove(policy);
-        return policy;
-    }
-
-    @Override
-    public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
-        return policies;
-    }
-
-    @Override
-    public UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException {
-        return new UsersAndAccessPolicies() {
-            @Override
-            public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) {
-                return policies.stream()
-                        .filter(policy -> policy.getResource().equals(resourceIdentifier) && policy.getAction().equals(action))
-                        .findFirst().orElse(null);
-            }
-
-            @Override
-            public User getUser(String identity) {
-                return getUserByIdentity(identity);
-            }
-
-            @Override
-            public Set<Group> getGroups(String userIdentity) {
-                User user = getUserByIdentity(userIdentity);
-                if (user == null) {
-                    return new HashSet<>();
-                } else {
-                    return groups.stream()
-                            .filter(g -> g.getUsers().contains(user.getIdentifier()))
-                            .collect(Collectors.toSet());
-                }
-            }
-        };
-    }
-
-    @Override
-    public void auditAccessAttempt(AuthorizationRequest request, AuthorizationResult result) {
-        audited.add(request);
-    }
-
-    public boolean isAudited(AuthorizationRequest request) {
-        return audited.contains(request);
-    }
-
-    @Override
-    public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
-
-    }
-
-    @Override
-    public void doOnConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
-
-    }
-
-    @Override
-    public void preDestruction() throws AuthorizerDestructionException {
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
index dbea636..8a359b6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
@@ -302,7 +302,7 @@ public class ControllerServiceDTO extends ComponentDTO {
         this.validationErrors = validationErrors;
     }
 
-    @ApiModelProperty(value = "Indicates whether the Processor is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Processor is valid)",
+    @ApiModelProperty(value = "Indicates whether the ControllerService is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the ControllerService is valid)",
         readOnly = true,
         allowableValues = VALID + ", " + INVALID + ", " + VALIDATING)
     public String getValidationStatus() {

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java
index 9e48d74..9aa5800 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java
@@ -94,7 +94,7 @@ public class ControllerServiceReferencingComponentDTO {
      * @return type for this component referencing a controller service
      */
     @ApiModelProperty(
-            value = "The type of the component referencing a controller service."
+            value = "The type of the component referencing a controller service in simple Java class name format without package name."
     )
     public String getType() {
         return type;

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java
new file mode 100644
index 0000000..f33338c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nifi.web.api.dto.status;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * General DTO for serializing the status of a component.
+ * This DTO is used to expose component status to API clients.
+ * This DTO must NOT contain any sensitive information as it can be returned
+ * to API clients regardless of having READ privilege to the component.
+ */
+@XmlType(name = "componentStatus")
+public class ComponentStatusDTO{
+
+    public static final String VALID = "VALID";
+    public static final String INVALID = "INVALID";
+    public static final String VALIDATING = "VALIDATING";
+
+    private String runStatus;
+    private String validationStatus;
+    private Integer activeThreadCount;
+
+    /**
+     * Sub-classes should override this method to provide API documentation using ApiModelProperty annotation with allowable values.
+     * @return the run status of the component
+     */
+    @ApiModelProperty(value = "The run status of this component",
+            readOnly = true,
+            allowableValues = "ENABLED, ENABLING, DISABLED, DISABLING")
+    public String getRunStatus() {
+        return runStatus;
+    }
+
+    public void setRunStatus(String runStatus) {
+        this.runStatus = runStatus;
+    }
+
+    @ApiModelProperty(value = "Indicates whether the component is valid, invalid, or still in the process of validating" +
+            " (i.e., it is unknown whether or not the component is valid)",
+            readOnly = true,
+            allowableValues = VALID + ", " + INVALID + ", " + VALIDATING)
+    public String getValidationStatus() {
+        return validationStatus;
+    }
+
+    public void setValidationStatus(String validationStatus) {
+        this.validationStatus = validationStatus;
+    }
+
+    /**
+     * @return number of active threads for this component
+     */
+    @ApiModelProperty(
+            value = "The number of active threads for the component."
+    )
+    public Integer getActiveThreadCount() {
+        return activeThreadCount;
+    }
+
+    public void setActiveThreadCount(Integer activeThreadCount) {
+        this.activeThreadCount = activeThreadCount;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java
new file mode 100644
index 0000000..891da9f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nifi.web.api.dto.status;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * DTO for serializing the status of a ControllerService.
+ */
+@XmlType(name = "controllerServiceStatus")
+public class ControllerServiceStatusDTO extends ComponentStatusDTO {
+
+    @ApiModelProperty(value = "The run status of this ControllerService",
+            readOnly = true,
+            allowableValues = "ENABLED, ENABLING, DISABLED, DISABLING")
+    @Override
+    public String getRunStatus() {
+        return super.getRunStatus();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java
index b71c42a..33db24b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java
@@ -33,6 +33,7 @@ public class RemoteProcessGroupStatusDTO {
     private String targetUri;
     private String transmissionStatus;
     private Date statsLastRefreshed;
+    private String validationStatus;
 
     private RemoteProcessGroupStatusSnapshotDTO aggregateSnapshot;
     private List<NodeRemoteProcessGroupStatusSnapshotDTO> nodeSnapshots;
@@ -119,4 +120,17 @@ public class RemoteProcessGroupStatusDTO {
     public void setStatsLastRefreshed(Date statsLastRefreshed) {
         this.statsLastRefreshed = statsLastRefreshed;
     }
+
+    @ApiModelProperty(value = "Indicates whether the component is valid, invalid, or still in the process of validating" +
+            " (i.e., it is unknown whether or not the component is valid)",
+            readOnly = true,
+            allowableValues = "VALID, INVALID, VALIDATING")
+    public String getValidationStatus() {
+        return validationStatus;
+    }
+
+    public void setValidationStatus(String validationStatus) {
+        this.validationStatus = validationStatus;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java
new file mode 100644
index 0000000..57ad553
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nifi.web.api.dto.status;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * DTO for serializing the status of a ReportingTask.
+ */
+@XmlType(name = "reportingTaskStatus")
+public class ReportingTaskStatusDTO extends ComponentStatusDTO {
+
+    @ApiModelProperty(value = "The run status of this ReportingTask",
+            readOnly = true,
+            allowableValues = "RUNNING, STOPPED")
+    @Override
+    public String getRunStatus() {
+        return super.getRunStatus();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java
new file mode 100644
index 0000000..2947668
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.RevisionDTO;
+
+import javax.xml.bind.annotation.XmlType;
+import java.util.Arrays;
+
+/**
+ * Run status for a given component.
+ */
+@XmlType(name = "componentRunStatus")
+public abstract class ComponentRunStatusEntity extends Entity {
+
+    private RevisionDTO revision;
+    private String state;
+    private Boolean disconnectedNodeAcknowledged;
+
+    /**
+     * @return revision for this request/response
+     */
+    @ApiModelProperty(
+            value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses."
+    )
+    public RevisionDTO getRevision() {
+        return revision;
+    }
+
+    public void setRevision(RevisionDTO revision) {
+        this.revision = revision;
+    }
+    /**
+     * Run status for this component.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the component."
+    )
+    public String getState() {
+        return this.state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    @ApiModelProperty(
+            value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed."
+    )
+    public Boolean isDisconnectedNodeAcknowledged() {
+        return disconnectedNodeAcknowledged;
+    }
+
+    public void setDisconnectedNodeAcknowledged(Boolean disconnectedNodeAcknowledged) {
+        this.disconnectedNodeAcknowledged = disconnectedNodeAcknowledged;
+    }
+
+    protected abstract String[] getSupportedState();
+
+    public void validateState() {
+        if (state == null || state.isEmpty()) {
+            throw new IllegalArgumentException("The desired state is not set.");
+        }
+
+        if (Arrays.stream(getSupportedState()).noneMatch(state::equals)) {
+            throw new IllegalArgumentException(String.format("The desired state '%s' is not supported.", state));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
index c9c3be3..1c2f4c0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
@@ -17,15 +17,36 @@
 package org.apache.nifi.web.api.entity;
 
 import javax.xml.bind.annotation.XmlRootElement;
+
+import io.swagger.annotations.ApiModelProperty;
 import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
+import org.apache.nifi.web.api.dto.status.ControllerServiceStatusDTO;
 
 /**
  * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a controller service.
  */
 @XmlRootElement(name = "controllerServiceEntity")
-public class ControllerServiceEntity extends ComponentEntity implements Permissible<ControllerServiceDTO> {
+public class ControllerServiceEntity extends ComponentEntity implements Permissible<ControllerServiceDTO>, OperationPermissible {
 
+    private String parentGroupId;
     private ControllerServiceDTO component;
+    private PermissionsDTO operatePermissions;
+    private ControllerServiceStatusDTO status;
+
+    /**
+     * @return The id for the parent group of this ControllerService
+     */
+    @ApiModelProperty(
+            value = "The id of parent process group of this ControllerService."
+    )
+    public String getParentGroupId() {
+        return parentGroupId;
+    }
+
+    public void setParentGroupId(String parentGroupId) {
+        this.parentGroupId = parentGroupId;
+    }
 
     /**
      * @return controller service that is being serialized
@@ -38,4 +59,35 @@ public class ControllerServiceEntity extends ComponentEntity implements Permissi
         this.component = component;
     }
 
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO permissions) {
+        this.operatePermissions = permissions;
+    }
+
+    /**
+     * @return The status for this ControllerService
+     */
+    @ApiModelProperty(
+            value = "The status for this ControllerService.",
+            readOnly = true
+    )
+    public ControllerServiceStatusDTO getStatus() {
+        return status;
+    }
+
+    public void setStatus(ControllerServiceStatusDTO status) {
+        this.status = status;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java
index 26c9835..17a4c40 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java
@@ -19,16 +19,19 @@ package org.apache.nifi.web.api.entity;
 
 import javax.xml.bind.annotation.XmlRootElement;
 
+import io.swagger.annotations.ApiModelProperty;
 import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 
 /**
  * A serialized representation of this class can be placed in the entity body of a response to the API.
  * This particular entity holds a reference to component that references a controller services.
  */
 @XmlRootElement(name = "controllerServiceReferencingComponentEntity")
-public class ControllerServiceReferencingComponentEntity extends ComponentEntity {
+public class ControllerServiceReferencingComponentEntity extends ComponentEntity implements OperationPermissible {
 
     private ControllerServiceReferencingComponentDTO component;
+    private PermissionsDTO operatePermissions;
 
     /**
      * @return controller service referencing components that is being serialized
@@ -41,4 +44,19 @@ public class ControllerServiceReferencingComponentEntity extends ComponentEntity
         this.component = component;
     }
 
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO permissions) {
+        this.operatePermissions = permissions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java
new file mode 100644
index 0000000..7970147
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Run status for a given ControllerService.
+ */
+@XmlType(name = "controllerServiceRunStatus")
+public class ControllerServiceRunStatusEntity extends ComponentRunStatusEntity {
+
+    private static String[] SUPPORTED_STATE = {"ENABLED", "DISABLED"};
+
+    @Override
+    protected String[] getSupportedState() {
+        return SUPPORTED_STATE;
+    }
+
+    /**
+     * Run status for this ControllerService.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the ControllerService.",
+            allowableValues = "ENABLED, DISABLED"
+    )
+    public String getState() {
+        return super.getState();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OperationPermissible.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OperationPermissible.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OperationPermissible.java
new file mode 100644
index 0000000..c6696d6
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OperationPermissible.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import org.apache.nifi.web.api.dto.PermissionsDTO;
+
+/**
+ * Provides access to a {@link PermissionsDTO} for its operations.
+ * This is intended to be used by classes that extend {@link Entity} which can be operated by operators
+ * who does not have 'write' or 'read' access to the component, but has 'operate' access.
+ */
+public interface OperationPermissible {
+
+    PermissionsDTO getOperatePermissions();
+
+    void setOperatePermissions(PermissionsDTO permissions);
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
index 2454af1..c72b6e3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
@@ -17,6 +17,7 @@
 package org.apache.nifi.web.api.entity;
 
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.status.PortStatusDTO;
 
@@ -26,11 +27,12 @@ import javax.xml.bind.annotation.XmlRootElement;
  * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to an input PortDTO.
  */
 @XmlRootElement(name = "portEntity")
-public class PortEntity extends ComponentEntity implements Permissible<PortDTO> {
+public class PortEntity extends ComponentEntity implements Permissible<PortDTO>, OperationPermissible {
 
     private PortDTO component;
     private PortStatusDTO status;
     private String portType;
+    private PermissionsDTO operatePermissions;
 
     /**
      * @return input PortDTO that are being serialized
@@ -66,4 +68,20 @@ public class PortEntity extends ComponentEntity implements Permissible<PortDTO>
     public void setPortType(String portType) {
         this.portType = portType;
     }
+
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO permissions) {
+        this.operatePermissions = permissions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java
new file mode 100644
index 0000000..a8b4471
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Run status for a given Port.
+ */
+@XmlType(name = "portRunStatus")
+public class PortRunStatusEntity extends ComponentRunStatusEntity {
+
+    private static String[] SUPPORTED_STATE = {"RUNNING", "STOPPED", "DISABLED"};
+
+    @Override
+    protected String[] getSupportedState() {
+        return SUPPORTED_STATE;
+    }
+
+    /**
+     * Run status for this Port.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the Port.",
+            allowableValues = "RUNNING, STOPPED, DISABLED"
+    )
+    public String getState() {
+        return super.getState();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
index 3607c0b..18b018d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
@@ -17,6 +17,7 @@
 package org.apache.nifi.web.api.entity;
 
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
 
@@ -26,11 +27,12 @@ import javax.xml.bind.annotation.XmlRootElement;
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ProcessorDTO.
  */
 @XmlRootElement(name = "processorEntity")
-public class ProcessorEntity extends ComponentEntity implements Permissible<ProcessorDTO> {
+public class ProcessorEntity extends ComponentEntity implements Permissible<ProcessorDTO>, OperationPermissible {
 
     private ProcessorDTO component;
     private String inputRequirement;
     private ProcessorStatusDTO status;
+    private PermissionsDTO operatePermissions;
 
     /**
      * The ProcessorDTO that is being serialized.
@@ -71,4 +73,20 @@ public class ProcessorEntity extends ComponentEntity implements Permissible<Proc
     public void setInputRequirement(String inputRequirement) {
         this.inputRequirement = inputRequirement;
     }
+
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO operatePermissions) {
+        this.operatePermissions = operatePermissions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java
new file mode 100644
index 0000000..4f8ef74
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Run status for a given Processor.
+ */
+@XmlType(name = "processorRunStatus")
+public class ProcessorRunStatusEntity extends ComponentRunStatusEntity {
+
+    private static String[] SUPPORTED_STATE = {"RUNNING", "STOPPED", "DISABLED"};
+
+    @Override
+    protected String[] getSupportedState() {
+        return SUPPORTED_STATE;
+    }
+
+    /**
+     * Run status for this Processor.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the Processor.",
+            allowableValues = "RUNNING, STOPPED, DISABLED"
+    )
+    public String getState() {
+        return super.getState();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java
new file mode 100644
index 0000000..e52bc94
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Run status for a given RemotePort.
+ */
+@XmlType(name = "remotePortRunStatus")
+public class RemotePortRunStatusEntity extends ComponentRunStatusEntity {
+
+    private static String[] SUPPORTED_STATE = {"TRANSMITTING", "STOPPED"};
+
+    @Override
+    protected String[] getSupportedState() {
+        return SUPPORTED_STATE;
+    }
+
+    /**
+     * Run status for this RemotePort.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the RemotePort.",
+            allowableValues = "TRANSMITTING, STOPPED"
+    )
+    public String getState() {
+        return super.getState();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
index 8b049a4..28a6418 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
@@ -17,6 +17,7 @@
 package org.apache.nifi.web.api.entity;
 
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
 
@@ -26,7 +27,7 @@ import javax.xml.bind.annotation.XmlRootElement;
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RemoteProcessGroupDTO.
  */
 @XmlRootElement(name = "remoteProcessGroupEntity")
-public class RemoteProcessGroupEntity extends ComponentEntity implements Permissible<RemoteProcessGroupDTO> {
+public class RemoteProcessGroupEntity extends ComponentEntity implements Permissible<RemoteProcessGroupDTO>, OperationPermissible {
 
     private RemoteProcessGroupDTO component;
     private RemoteProcessGroupStatusDTO status;
@@ -34,6 +35,8 @@ public class RemoteProcessGroupEntity extends ComponentEntity implements Permiss
     private Integer inputPortCount;
     private Integer outputPortCount;
 
+    private PermissionsDTO operatePermissions;
+
     /**
      * The RemoteProcessGroupDTO that is being serialized.
      *
@@ -88,4 +91,20 @@ public class RemoteProcessGroupEntity extends ComponentEntity implements Permiss
     public void setOutputPortCount(Integer outputPortCount) {
         this.outputPortCount = outputPortCount;
     }
+
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO permissions) {
+        this.operatePermissions = permissions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java
index 6216f95..837066f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java
@@ -18,15 +18,18 @@ package org.apache.nifi.web.api.entity;
 
 import javax.xml.bind.annotation.XmlRootElement;
 
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
 
 /**
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RemoteProcessGroupPortDTO.
  */
 @XmlRootElement(name = "remoteProcessGroupPortEntity")
-public class RemoteProcessGroupPortEntity extends ComponentEntity {
+public class RemoteProcessGroupPortEntity extends ComponentEntity implements OperationPermissible {
 
     private RemoteProcessGroupPortDTO remoteProcessGroupPort;
+    private PermissionsDTO operatePermissions;
 
     /**
      * The RemoteProcessGroupPortDTO that is being serialized.
@@ -41,4 +44,19 @@ public class RemoteProcessGroupPortEntity extends ComponentEntity {
         this.remoteProcessGroupPort = remoteProcessGroupPort;
     }
 
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO operatePermissions) {
+        this.operatePermissions = operatePermissions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java
index a7bf6b3..3461bb2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java
@@ -18,15 +18,22 @@ package org.apache.nifi.web.api.entity;
 
 import javax.xml.bind.annotation.XmlRootElement;
 
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.PermissionsDTO;
 import org.apache.nifi.web.api.dto.ReportingTaskDTO;
+import org.apache.nifi.web.api.dto.status.ReportingTaskStatusDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
 
 /**
  * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a reporting task.
  */
 @XmlRootElement(name = "reportingTaskEntity")
-public class ReportingTaskEntity extends ComponentEntity implements Permissible<ReportingTaskDTO> {
+public class ReportingTaskEntity extends ComponentEntity implements Permissible<ReportingTaskDTO>, OperationPermissible {
 
     private ReportingTaskDTO component;
+    private PermissionsDTO operatePermissions;
+    private ReportingTaskStatusDTO status;
 
     /**
      * @return reporting task that is being serialized
@@ -41,4 +48,34 @@ public class ReportingTaskEntity extends ComponentEntity implements Permissible<
         this.component = component;
     }
 
+    /**
+     * @return The permissions for this component operations
+     */
+    @ApiModelProperty(
+            value = "The permissions for this component operations."
+    )
+    @Override
+    public PermissionsDTO getOperatePermissions() {
+        return operatePermissions;
+    }
+
+    @Override
+    public void setOperatePermissions(PermissionsDTO permissions) {
+        this.operatePermissions = permissions;
+    }
+
+    /**
+     * @return The status for this ReportingTask
+     */
+    @ApiModelProperty(
+            value = "The status for this ReportingTask.",
+            readOnly = true
+    )
+    public ReportingTaskStatusDTO getStatus() {
+        return status;
+    }
+
+    public void setStatus(ReportingTaskStatusDTO status) {
+        this.status = status;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java
new file mode 100644
index 0000000..6d01e19
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Run status for a given ReportingTask.
+ */
+@XmlType(name = "reportingTaskRunStatus")
+public class ReportingTaskRunStatusEntity extends ComponentRunStatusEntity {
+
+    private static String[] SUPPORTED_STATE = {"RUNNING", "STOPPED"};
+
+    @Override
+    protected String[] getSupportedState() {
+        return SUPPORTED_STATE;
+    }
+
+    /**
+     * Run status for this ReportingTask.
+     * @return The run status
+     */
+    @ApiModelProperty(
+            value = "The run status of the ReportingTask.",
+            allowableValues = "RUNNING, STOPPED"
+    )
+    public String getState() {
+        return super.getState();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
index b89e7e6..fafdf26 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
@@ -47,5 +47,11 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-mock-authorizer</artifactId>
+            <version>1.8.0-SNAPSHOT</version>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java
new file mode 100644
index 0000000..ec0d875
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.resource;
+
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Authorizable for a component that can be scheduled by operators.
+ */
+public class OperationAuthorizable implements Authorizable, EnforcePolicyPermissionsThroughBaseResource {
+    private static Logger logger = LoggerFactory.getLogger(OperationAuthorizable.class);
+    private final Authorizable baseAuthorizable;
+
+    public OperationAuthorizable(final Authorizable baseAuthorizable) {
+        this.baseAuthorizable = baseAuthorizable;
+    }
+
+    @Override
+    public Authorizable getParentAuthorizable() {
+        // Need to return parent operation authorizable. E.g. /operation/processor/xxxx -> /operation/process-group/yyyy -> /operation/process-group/root
+        if (baseAuthorizable.getParentAuthorizable() == null) {
+            return null;
+        } else {
+            return new OperationAuthorizable(baseAuthorizable.getParentAuthorizable());
+        }
+    }
+
+    @Override
+    public Authorizable getBaseAuthorizable() {
+        return baseAuthorizable;
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getOperationResource(baseAuthorizable.getResource());
+    }
+
+    /**
+     * <p>Authorize the request operation action with the resource using base authorizable and operation authorizable combination.</p>
+     *
+     * <p>This method authorizes the request with the base authorizable first with WRITE action. If the request is allowed, then finish authorization.
+     * If the base authorizable denies the request, then it checks if the user has WRITE permission for '/operation/{componentType}/{id}'.</p>
+     */
+    public static void authorizeOperation(final Authorizable baseAuthorizable, final Authorizer authorizer, final NiFiUser user) {
+        try {
+            baseAuthorizable.authorize(authorizer, RequestAction.WRITE, user);
+        } catch (AccessDeniedException e) {
+            logger.debug("Authorization failed with {}. Try authorizing with OperationAuthorizable.", baseAuthorizable, e);
+            // Always use WRITE action for operation.
+            new OperationAuthorizable(baseAuthorizable).authorize(authorizer, RequestAction.WRITE, user);
+        }
+
+    }
+
+    /**
+     * Check if the request is authorized.
+     *
+     * @return True if the WRITE request is allowed by the base authorizable, or the user has WRITE permission for '/operation/{componentType}/id'.
+     */
+    public static boolean isOperationAuthorized(final Authorizable baseAuthorizable, final Authorizer authorizer, final NiFiUser user) {
+        return baseAuthorizable.isAuthorized(authorizer, RequestAction.WRITE, user)
+                || new OperationAuthorizable(baseAuthorizable).isAuthorized(authorizer, RequestAction.WRITE, user);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
index f2cec02..9d3b532 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
@@ -442,6 +442,33 @@ public final class ResourceFactory {
     }
 
     /**
+     * Gets a Resource for accessing component operations.
+     *
+     * @param resource      The resource being accessed
+     * @return              The resource
+     */
+    public static Resource getOperationResource(final Resource resource) {
+        Objects.requireNonNull(resource, "The resource type must be specified.");
+
+        return new Resource() {
+            @Override
+            public String getIdentifier() {
+                return ResourceType.Operation.getValue() + resource.getIdentifier();
+            }
+
+            @Override
+            public String getName() {
+                return "Operations for" + resource.getName();
+            }
+
+            @Override
+            public String getSafeDescription() {
+                return "Operations for" + resource.getSafeDescription();
+            }
+        };
+    }
+
+    /**
      * Gets a Resource for accessing a component configuration.
      *
      * @param resourceType  The type of resource being accessed

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
index d2d3126..a24b904 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
@@ -39,6 +39,7 @@ public enum ResourceType {
     DataTransfer("/data-transfer"),
     System("/system"),
     RestrictedComponents("/restricted-components"),
+    Operation("/operation"),
     Template("/templates"),
     Tenant("/tenants");
 
@@ -52,20 +53,20 @@ public enum ResourceType {
         return value;
     }
 
-    public static ResourceType valueOfValue(final String rawValue) {
-        ResourceType type = null;
+    /**
+     * Get ResourceType from a raw resource value.
+     * E.g. From "rovenance-data/processors/7ce897d6-0164-1000-fc87-caee3b08ba47", ProvenanceData will be returned.
+     * @param rawValue the raw resource string representation
+     * @return the type of the specified resource, or null if not found
+     */
+    public static ResourceType fromRawValue(final String rawValue) throws IllegalArgumentException {
 
         for (final ResourceType rt : values()) {
-            if (rt.getValue().equals(rawValue)) {
-                type = rt;
-                break;
+            if (rt.getValue().equals(rawValue) || rawValue.startsWith(rt.getValue() + "/")) {
+                return rt;
             }
         }
 
-        if (type == null) {
-            throw new IllegalArgumentException("Unknown resource type value " + rawValue);
-        }
-
-        return type;
+        return null;
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/test/java/org/apache/nifi/authorization/resource/OperationAuthorizableTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/test/java/org/apache/nifi/authorization/resource/OperationAuthorizableTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/test/java/org/apache/nifi/authorization/resource/OperationAuthorizableTest.java
new file mode 100644
index 0000000..87a4fc4
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/test/java/org/apache/nifi/authorization/resource/OperationAuthorizableTest.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.resource;
+
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.MockPolicyBasedAuthorizer;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.User;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
+import org.junit.Test;
+
+import static org.apache.nifi.authorization.RequestAction.READ;
+import static org.apache.nifi.authorization.RequestAction.WRITE;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class OperationAuthorizableTest {
+
+    private static final User AUTH_USER = new User.Builder()
+            .identity("user-a")
+            .identifierGenerateRandom()
+            .build();
+    private static final StandardNiFiUser USER = new StandardNiFiUser.Builder()
+            .identity(AUTH_USER.getIdentity())
+            .build();
+    private final MockProcessGroup ROOT_PG = new MockProcessGroup("root", null);
+    private final MockProcessGroup PG1 = new MockProcessGroup("pg-1", ROOT_PG);
+    private final Authorizable PROCESSOR = new MockProcessor("component-1", PG1);
+
+    private class MockProcessGroup implements Authorizable {
+        private final String identifier;
+        private final MockProcessGroup parent;
+
+        private MockProcessGroup(String identifier, MockProcessGroup parent) {
+            this.identifier = identifier;
+            this.parent = parent;
+        }
+
+        public String getIdentifier() {
+            return identifier;
+        }
+
+        @Override
+        public Authorizable getParentAuthorizable() {
+            return parent;
+        }
+
+        @Override
+        public Resource getResource() {
+            return ResourceFactory.getComponentResource(ResourceType.ProcessGroup, identifier, identifier);
+        }
+    }
+
+    private class MockProcessor implements ComponentAuthorizable {
+        private final String identifier;
+        private final MockProcessGroup processGroup;
+
+        private MockProcessor(String identifier, MockProcessGroup processGroup) {
+            this.identifier = identifier;
+            this.processGroup = processGroup;
+        }
+
+        @Override
+        public String getIdentifier() {
+            return identifier;
+        }
+
+        @Override
+        public String getProcessGroupIdentifier() {
+            return processGroup.getIdentifier();
+        }
+
+        @Override
+        public Authorizable getParentAuthorizable() {
+            return processGroup;
+        }
+
+        @Override
+        public Resource getResource() {
+            return ResourceFactory.getComponentResource(ResourceType.Processor, identifier, identifier);
+        }
+    }
+
+    private void shouldBeDenied(String message, Runnable test) {
+        try {
+            test.run();
+            fail(message);
+        } catch (AccessDeniedException e) {
+            assertNotNull(e);
+        }
+    }
+
+    @Test()
+    public void testUnauthorizedRead() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+
+        // The user should not be able to access the component in any way.
+        shouldBeDenied("Component WRITE should be denied",
+                () -> PROCESSOR.authorize(authorizer, WRITE, USER));
+
+        shouldBeDenied("Component READ should be denied",
+                () -> PROCESSOR.authorize(authorizer, READ, USER));
+
+        shouldBeDenied("Operation should be denied",
+                () -> OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER));
+    }
+
+    @Test()
+    public void testAuthorizedByComponentRead() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+        authorizer.addUser(AUTH_USER);
+        authorizer.addAccessPolicy(new AccessPolicy.Builder()
+                .identifierGenerateRandom()
+                .addUser(AUTH_USER.getIdentifier())
+                .resource("/processors/component-1")
+                .action(READ)
+                .build());
+
+        PROCESSOR.authorize(authorizer, READ, USER);
+
+        // If the user has only READ access to the base component WRITE and operation should be denied
+        shouldBeDenied("Component WRITE should be denied",
+                () -> PROCESSOR.authorize(authorizer, WRITE, USER));
+
+        shouldBeDenied("Operation WRITE should be denied",
+                () -> OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER));
+    }
+
+    @Test()
+    public void testAuthorizedByComponentWrite() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+        authorizer.addUser(AUTH_USER);
+        authorizer.addAccessPolicy(new AccessPolicy.Builder()
+                .identifierGenerateRandom()
+                .addUser(AUTH_USER.getIdentifier())
+                .resource("/processors/component-1")
+                .action(WRITE)
+                .build());
+
+        // If the user has WRITE access to the base component, operation access should be allowed, too
+        PROCESSOR.authorize(authorizer, WRITE, USER);
+        OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER);
+
+        // But READ should be denied
+        shouldBeDenied("Component READ should be denied",
+                () -> PROCESSOR.authorize(authorizer, READ, USER));
+    }
+
+    @Test()
+    public void testAuthorizedByComponentParentWrite() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+        authorizer.addUser(AUTH_USER);
+        authorizer.addAccessPolicy(new AccessPolicy.Builder()
+                .identifierGenerateRandom()
+                .addUser(AUTH_USER.getIdentifier())
+                .resource("/process-groups/root")
+                .action(WRITE)
+                .build());
+
+        // If the user has WRITE access to the base component, operation access should be allowed, too
+        PROCESSOR.authorize(authorizer, WRITE, USER);
+        OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER);
+
+        // But READ should be denied
+        shouldBeDenied("Component READ should be denied",
+                () -> PROCESSOR.authorize(authorizer, READ, USER));
+
+    }
+
+    @Test()
+    public void testAuthorizedByOperationWrite() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+        authorizer.addUser(AUTH_USER);
+        authorizer.addAccessPolicy(new AccessPolicy.Builder()
+                .identifierGenerateRandom()
+                .addUser(AUTH_USER.getIdentifier())
+                .resource("/operation/processors/component-1")
+                .action(WRITE)
+                .build());
+
+        // Operation should be allowed, too.
+        OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER);
+
+        // If the user only has the operation permissions, then component access should be denied.
+        shouldBeDenied("Component READ should be denied",
+                () -> PROCESSOR.authorize(authorizer, READ, USER));
+        shouldBeDenied("Component WRITE should be denied",
+                () -> PROCESSOR.authorize(authorizer, WRITE, USER));
+    }
+
+    @Test()
+    public void testAuthorizedByOperationParentWrite() {
+        final MockPolicyBasedAuthorizer authorizer = new MockPolicyBasedAuthorizer();
+        authorizer.addUser(AUTH_USER);
+        authorizer.addAccessPolicy(new AccessPolicy.Builder()
+                .identifierGenerateRandom()
+                .addUser(AUTH_USER.getIdentifier())
+                .resource("/operation/process-groups/root")
+                .action(WRITE)
+                .build());
+
+        // Operation should be allowed.
+        OperationAuthorizable.authorizeOperation(PROCESSOR, authorizer, USER);
+
+        // If the user only has the operation permissions, then component access should be denied.
+        shouldBeDenied("Component READ should be denied",
+                () -> PROCESSOR.authorize(authorizer, READ, USER));
+        shouldBeDenied("Component WRITE should be denied",
+                () -> PROCESSOR.authorize(authorizer, WRITE, USER));
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f570cb98/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java
index f7c28fd..408e99f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java
@@ -19,6 +19,7 @@ package org.apache.nifi.cluster.manager;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.web.api.entity.BulletinEntity;
 import org.apache.nifi.web.api.entity.ComponentEntity;
+import org.apache.nifi.web.api.entity.OperationPermissible;
 import org.apache.nifi.web.api.entity.Permissible;
 
 import java.util.ArrayList;
@@ -44,6 +45,11 @@ public interface ComponentEntityMerger<EntityType extends ComponentEntity & Perm
         for (final Map.Entry<NodeIdentifier, EntityType> entry : entityMap.entrySet()) {
             final EntityType entity = entry.getValue();
             PermissionsDtoMerger.mergePermissions(clientEntity.getPermissions(), entity.getPermissions());
+            if (clientEntity instanceof OperationPermissible && entity instanceof  OperationPermissible) {
+                PermissionsDtoMerger.mergePermissions(
+                        ((OperationPermissible) clientEntity).getOperatePermissions(),
+                        ((OperationPermissible) entity).getOperatePermissions());
+            }
         }
 
         if (clientEntity.getPermissions().getCanRead()) {