From f0811ca45adf15edf02f0f2d5f1d2d6929edd329 Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Thu, 23 Jun 2016 15:55:18 -0400 Subject: [PATCH] NIFI-1554: - Addressing access controls for the Controller resource. - Addressing access controls for RAW site to site clients. - Addressing access controls for downloading content (from provenance and queue). - Addressing access controls for accessing queues. - Addressing access controls for cluster endpoints. - Addressing access controls for counter endpoints. - Removing redundant authorization calls. NIFI-2044: - Requiring revision when creating components. - Requiring component creation over POST requests. NIFI-1901 - Continuing to restore access control tests. - Converting access control tests to itegration tests. - Restoring contrib check to travis build. - This closes #567 --- .travis.yml | 2 +- .../java/org/apache/nifi/web/Revision.java | 27 +- .../org/apache/nifi/web/TestRevision.java | 61 + .../nifi-framework/nifi-authorizer/pom.xml | 4 + .../api/dto/ControllerConfigurationDTO.java | 54 +- .../web/api/dto/FlowConfigurationDTO.java | 80 + .../apache/nifi/web/api/dto/RevisionDTO.java | 3 +- .../entity/ControllerConfigurationEntity.java | 29 +- .../api/entity/FlowConfigurationEntity.java | 48 + .../authorization/resource/Authorizable.java | 26 +- .../resource/ResourceFactory.java | 44 + .../authorization/resource/ResourceType.java | 1 + .../nifi/authorization/user/NiFiUser.java | 4 - .../ReportingTasksEndpointMerger.java | 2 +- .../nifi/web/revision/UpdateRevisionTask.java | 32 - .../controller/StandardFlowServiceTest.java | 22 +- .../scheduling/TestProcessorLifecycle.java | 42 +- .../nifi/remote/StandardRootGroupPort.java | 28 +- ...ttpServletConfigurationRequestContext.java | 6 +- .../nifi-web/nifi-web-api/pom.xml | 2 +- .../apache/nifi/web/AuthorizableLookup.java | 7 + .../apache/nifi/web/NiFiServiceFacade.java | 70 +- .../nifi/web/StandardAuthorizableLookup.java | 5 + .../nifi/web/StandardNiFiServiceFacade.java | 467 +++--- .../StandardNiFiWebConfigurationContext.java | 12 +- .../org/apache/nifi/web/UpdateResult.java | 40 - .../nifi/web/api/AccessPolicyResource.java | 20 +- .../apache/nifi/web/api/ClusterResource.java | 357 ----- .../nifi/web/api/ConnectionResource.java | 17 +- .../nifi/web/api/ControllerResource.java | 651 +++++--- .../web/api/ControllerServiceResource.java | 23 +- .../apache/nifi/web/api/CountersResource.java | 252 ++++ .../nifi/web/api/FlowFileQueueResource.java | 69 +- .../org/apache/nifi/web/api/FlowResource.java | 386 ++++- .../apache/nifi/web/api/FunnelResource.java | 17 +- .../apache/nifi/web/api/HistoryResource.java | 525 ------- .../nifi/web/api/InputPortResource.java | 53 +- .../apache/nifi/web/api/LabelResource.java | 51 +- .../org/apache/nifi/web/api/NodeResource.java | 219 --- .../nifi/web/api/OutputPortResource.java | 53 +- .../nifi/web/api/ProcessGroupResource.java | 151 +- .../nifi/web/api/ProcessorResource.java | 17 +- .../web/api/RemoteProcessGroupResource.java | 15 +- .../nifi/web/api/ReportingTaskResource.java | 23 +- .../nifi/web/api/SiteToSiteResource.java | 25 +- .../nifi/web/api/UserGroupsResource.java | 16 +- .../apache/nifi/web/api/UsersResource.java | 16 +- .../apache/nifi/web/api/dto/DtoFactory.java | 7 +- .../nifi/web/api/dto/EntityFactory.java | 9 +- .../nifi/web/controller/ControllerFacade.java | 107 +- .../web/dao/impl/StandardConnectionDAO.java | 31 +- .../impl/StandardControllerServiceDAO.java | 7 +- .../main/resources/nifi-web-api-context.xml | 19 +- .../web/StandardNiFiServiceFacadeSpec.groovy | 224 ++- .../nifi/integration/NiFiWebApiTest.java | 6 +- .../accesscontrol/AccessControlHelper.java | 31 + .../accesscontrol/AdminAccessControlTest.java | 1010 ------------- .../accesscontrol/DfmAccessControlTest.java | 1322 ----------------- ...ntTest.java => ITAccessTokenEndpoint.java} | 4 +- ...st.java => ITConnectionAccessControl.java} | 8 +- .../ITCountersAccessControl.java | 86 ++ .../accesscontrol/ITFlowAccessControl.java | 245 +++ ...olTest.java => ITFunnelAccessControl.java} | 4 +- ...est.java => ITInputPortAccessControl.java} | 4 +- ...rolTest.java => ITLabelAccessControl.java} | 4 +- ...st.java => ITOutputPortAccessControl.java} | 4 +- ....java => ITProcessGroupAccessControl.java} | 4 +- ...est.java => ITProcessorAccessControl.java} | 4 +- .../ReadOnlyAccessControlTest.java | 983 ------------ .../util/NiFiFlowTestAuthorizer.java | 87 ++ .../integration/util/NiFiTestAuthorizer.java | 4 +- .../nifi/integration/util/NiFiTestUser.java | 16 +- .../nifi/web/api/TestSiteToSiteResource.java | 4 +- .../org.apache.nifi.authorization.Authorizer | 3 +- .../resources/access-control/authorizers.xml | 4 + .../propertytable/jquery.propertytable.js | 5 + .../components/nf-ng-funnel-component.js | 5 + .../components/nf-ng-group-component.js | 5 + .../components/nf-ng-input-port-component.js | 5 + .../components/nf-ng-label-component.js | 5 + .../components/nf-ng-output-port-component.js | 5 + .../components/nf-ng-processor-component.js | 5 + .../nf-ng-remote-process-group-component.js | 5 + .../src/main/webapp/js/nf/canvas/nf-canvas.js | 8 +- .../nf/canvas/nf-connection-configuration.js | 5 + .../js/nf/canvas/nf-controller-service.js | 4 +- .../js/nf/canvas/nf-controller-services.js | 5 + .../nf/canvas/nf-processor-configuration.js | 2 +- .../webapp/js/nf/canvas/nf-reporting-task.js | 4 +- .../main/webapp/js/nf/canvas/nf-settings.js | 17 +- .../webapp/js/nf/cluster/nf-cluster-table.js | 2 +- .../js/nf/counters/nf-counters-table.js | 2 +- .../webapp/js/nf/history/nf-history-model.js | 2 +- .../webapp/js/nf/history/nf-history-table.js | 2 +- .../main/webapp/js/nf/nf-processor-details.js | 2 +- .../js/nf/provenance/nf-provenance-table.js | 2 +- .../webapp/js/nf/provenance/nf-provenance.js | 2 +- .../webapp/js/nf/summary/nf-cluster-search.js | 2 +- .../webapp/js/nf/summary/nf-summary-table.js | 6 +- .../main/webapp/js/nf/summary/nf-summary.js | 2 +- .../processors/standard/TestGetJMSQueue.java | 33 +- .../nifi/controller/MonitorMemoryTest.java | 14 +- .../update/attributes/api/RuleResource.java | 2 +- 103 files changed, 2802 insertions(+), 5671 deletions(-) create mode 100644 nifi-api/src/test/java/org/apache/nifi/web/TestRevision.java create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/UpdateResult.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/HistoryResource.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/NodeResource.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{AccessTokenEndpointTest.java => ITAccessTokenEndpoint.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{ConnectionAccessControlTest.java => ITConnectionAccessControl.java} (97%) create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITCountersAccessControl.java create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITFlowAccessControl.java rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{FunnelAccessControlTest.java => ITFunnelAccessControl.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{InputPortAccessControlTest.java => ITInputPortAccessControl.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{LabelAccessControlTest.java => ITLabelAccessControl.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{OutputPortAccessControlTest.java => ITOutputPortAccessControl.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{ProcessGroupAccessControlTest.java => ITProcessGroupAccessControl.java} (99%) rename nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/{ProcessorAccessControlTest.java => ITProcessorAccessControl.java} (99%) delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiFlowTestAuthorizer.java diff --git a/.travis.yml b/.travis.yml index db579ce0f5..811a4c2d0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,4 @@ before_install: - sed -e "s/^\\(127\\.0\\.0\\.1.*\\)/\\1 $(hostname | cut -c1-63)/" /etc/hosts | sudo tee /etc/hosts - sed -i.bak -e 's|https://nexus.codehaus.org/snapshots/|https://oss.sonatype.org/content/repositories/codehaus-snapshots/|g' ~/.m2/settings.xml -script: mvn clean install -T4 +script: mvn clean install -Pcontrib-check diff --git a/nifi-api/src/main/java/org/apache/nifi/web/Revision.java b/nifi-api/src/main/java/org/apache/nifi/web/Revision.java index 1308e1b752..d768faa409 100644 --- a/nifi-api/src/main/java/org/apache/nifi/web/Revision.java +++ b/nifi-api/src/main/java/org/apache/nifi/web/Revision.java @@ -17,7 +17,6 @@ package org.apache.nifi.web; import java.io.Serializable; -import java.util.Objects; /** * A model object representing a revision. Equality is defined as matching @@ -46,15 +45,17 @@ public class Revision implements Serializable { */ private final String componentId; - @Deprecated - public Revision(Long revision, String clientId) { - this(revision, clientId, "root"); // TODO: remove this constructor. This is to bridge the gap right now - } + public Revision(Long version, String clientId, String componentId) { + if (version == null) { + throw new IllegalArgumentException("The revision must be specified."); + } + if (componentId == null) { + throw new IllegalArgumentException("The componentId must be specified."); + } - public Revision(Long revision, String clientId, String componentId) { - this.version = revision; + this.version = version; this.clientId = clientId; - this.componentId = Objects.requireNonNull(componentId); + this.componentId = componentId; } public String getClientId() { @@ -69,6 +70,16 @@ public class Revision implements Serializable { return componentId; } + /** + * Returns a new Revision that has the same Client ID and Component ID as this one + * but with a larger version + * + * @return the updated Revision + */ + public Revision incrementRevision(final String clientId) { + return new Revision(version + 1, clientId, componentId); + } + @Override public boolean equals(final Object obj) { if (obj == null) { diff --git a/nifi-api/src/test/java/org/apache/nifi/web/TestRevision.java b/nifi-api/src/test/java/org/apache/nifi/web/TestRevision.java new file mode 100644 index 0000000000..6d513fd79e --- /dev/null +++ b/nifi-api/src/test/java/org/apache/nifi/web/TestRevision.java @@ -0,0 +1,61 @@ +/* + * 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; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * + */ +public class TestRevision { + + @Test(expected = IllegalArgumentException.class) + public void testNullVersion() throws Exception { + new Revision(null, "client-id", "component-id"); + } + + @Test(expected = IllegalArgumentException.class) + public void testNullComponentId() throws Exception { + new Revision(0l, "client-id", null); + } + + @Test + public void testIncrementRevision() throws Exception { + final String clientId = "client-id"; + final String componentId = "component-id"; + final Revision revision = new Revision(0l, clientId, componentId); + final Revision updatedRevision = revision.incrementRevision(clientId); + assertEquals(1, updatedRevision.getVersion().longValue()); + assertEquals(clientId, updatedRevision.getClientId()); + assertEquals(componentId, updatedRevision.getComponentId()); + } + + @Test + public void testIncrementRevisionNewClient() throws Exception { + final String clientId = "client-id"; + final String newClientId = "new-client-id"; + final String componentId = "component-id"; + final Revision revision = new Revision(0l, clientId, componentId); + final Revision updatedRevision = revision.incrementRevision(newClientId); + assertEquals(1, updatedRevision.getVersion().longValue()); + assertEquals(newClientId, updatedRevision.getClientId()); + assertEquals(componentId, updatedRevision.getComponentId()); + } + +} 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 b8e1652fb4..ee9f85a3a9 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 @@ -69,6 +69,10 @@ org.apache.nifi nifi-nar-utils + + org.apache.nifi + nifi-properties + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java index 2c7edf7784..aee65b4c4d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java @@ -17,26 +17,18 @@ package org.apache.nifi.web.api.dto; import com.wordnik.swagger.annotations.ApiModelProperty; -import org.apache.nifi.web.api.dto.util.TimeAdapter; import javax.xml.bind.annotation.XmlType; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import java.util.Date; /** * Details for the controller configuration. */ -@XmlType(name = "config") +@XmlType(name = "controllerConfiguration") public class ControllerConfigurationDTO { private Integer maxTimerDrivenThreadCount; private Integer maxEventDrivenThreadCount; - private Long autoRefreshIntervalSeconds; - - private Date currentTime; - private Integer timeOffset; - /** * @return maximum number of timer driven threads this NiFi has available */ @@ -64,48 +56,4 @@ public class ControllerConfigurationDTO { public void setMaxEventDrivenThreadCount(Integer maxEventDrivenThreadCount) { this.maxEventDrivenThreadCount = maxEventDrivenThreadCount; } - - /** - * @return interval in seconds between the automatic NiFi refresh requests. This value is read only - */ - @ApiModelProperty( - value = "The interval in seconds between the automatic NiFi refresh requests.", - readOnly = true - ) - public Long getAutoRefreshIntervalSeconds() { - return autoRefreshIntervalSeconds; - } - - public void setAutoRefreshIntervalSeconds(Long autoRefreshIntervalSeconds) { - this.autoRefreshIntervalSeconds = autoRefreshIntervalSeconds; - } - - /** - * @return current time on the server - */ - @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system." - ) - public Date getCurrentTime() { - return currentTime; - } - - public void setCurrentTime(Date currentTime) { - this.currentTime = currentTime; - } - - /** - * @return time offset of the server - */ - @ApiModelProperty( - value = "The time offset of the system." - ) - public Integer getTimeOffset() { - return timeOffset; - } - - public void setTimeOffset(Integer timeOffset) { - this.timeOffset = timeOffset; - } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java new file mode 100644 index 0000000000..d5028d254c --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.web.api.dto; + +import com.wordnik.swagger.annotations.ApiModelProperty; +import org.apache.nifi.web.api.dto.util.TimeAdapter; + +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.Date; + +/** + * Details for the controller configuration. + */ +@XmlType(name = "flowConfiguration") +public class FlowConfigurationDTO { + + private Long autoRefreshIntervalSeconds; + + private Date currentTime; + private Integer timeOffset; + + /** + * @return interval in seconds between the automatic NiFi refresh requests. This value is read only + */ + @ApiModelProperty( + value = "The interval in seconds between the automatic NiFi refresh requests.", + readOnly = true + ) + public Long getAutoRefreshIntervalSeconds() { + return autoRefreshIntervalSeconds; + } + + public void setAutoRefreshIntervalSeconds(Long autoRefreshIntervalSeconds) { + this.autoRefreshIntervalSeconds = autoRefreshIntervalSeconds; + } + + /** + * @return current time on the server + */ + @XmlJavaTypeAdapter(TimeAdapter.class) + @ApiModelProperty( + value = "The current time on the system." + ) + public Date getCurrentTime() { + return currentTime; + } + + public void setCurrentTime(Date currentTime) { + this.currentTime = currentTime; + } + + /** + * @return time offset of the server + */ + @ApiModelProperty( + value = "The time offset of the system." + ) + public Integer getTimeOffset() { + return timeOffset; + } + + public void setTimeOffset(Integer timeOffset) { + this.timeOffset = timeOffset; + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java index 0e673f8dd7..e50e6e1ab1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java @@ -70,7 +70,8 @@ public class RevisionDTO { * @return The user that last modified the flow */ @ApiModelProperty( - value = "The user that last modified the flow." + value = "The user that last modified the flow.", + readOnly = true ) public String getLastModifier() { return lastModifier; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java index 4b1188c165..066950e471 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java @@ -20,8 +20,11 @@ import com.wordnik.swagger.annotations.ApiModelProperty; import org.apache.nifi.web.api.dto.AccessPolicyDTO; import org.apache.nifi.web.api.dto.ControllerConfigurationDTO; import org.apache.nifi.web.api.dto.RevisionDTO; +import org.apache.nifi.web.api.dto.util.TimeAdapter; import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.Date; /** * 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 ControllerConfigurationDTO. @@ -29,7 +32,8 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "controllerConfigurationEntity") public class ControllerConfigurationEntity extends Entity { - private ControllerConfigurationDTO config; + private Date currentTime; + private ControllerConfigurationDTO controllerConfiguration; private RevisionDTO revision; private AccessPolicyDTO accessPolicy; @@ -59,12 +63,12 @@ public class ControllerConfigurationEntity extends Entity { @ApiModelProperty( value = "The controller configuration." ) - public ControllerConfigurationDTO getConfig() { - return config; + public ControllerConfigurationDTO getControllerConfiguration() { + return controllerConfiguration; } - public void setConfig(ControllerConfigurationDTO config) { - this.config = config; + public void setControllerConfiguration(ControllerConfigurationDTO controllerConfiguration) { + this.controllerConfiguration = controllerConfiguration; } /** @@ -82,4 +86,19 @@ public class ControllerConfigurationEntity extends Entity { public void setAccessPolicy(AccessPolicyDTO accessPolicy) { this.accessPolicy = accessPolicy; } + + /** + * @return current time on the server + */ + @XmlJavaTypeAdapter(TimeAdapter.class) + @ApiModelProperty( + value = "The current time on the system." + ) + public Date getCurrentTime() { + return currentTime; + } + + public void setCurrentTime(Date currentTime) { + this.currentTime = currentTime; + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java new file mode 100644 index 0000000000..54af4d4e17 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.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 com.wordnik.swagger.annotations.ApiModelProperty; +import org.apache.nifi.web.api.dto.FlowConfigurationDTO; + +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 FlowConfigurationDTO. + */ +@XmlRootElement(name = "flowConfigurationEntity") +public class FlowConfigurationEntity extends Entity { + + private FlowConfigurationDTO flowConfiguration; + + /** + * The FlowConfigurationDTO that is being serialized. + * + * @return The FlowConfigurationDTO object + */ + @ApiModelProperty( + value = "The controller configuration." + ) + public FlowConfigurationDTO getFlowConfiguration() { + return flowConfiguration; + } + + public void setFlowConfiguration(FlowConfigurationDTO flowConfiguration) { + this.flowConfiguration = flowConfiguration; + } + +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java index c897be279b..50f7288d76 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java @@ -65,18 +65,30 @@ public interface Authorizable { * @return is authorized */ default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action) { - final NiFiUser user = NiFiUserUtils.getNiFiUser(); + return checkAuthorization(authorizer, action, NiFiUserUtils.getNiFiUser()); + } + /** + * Returns the result of an authorization request for the specified user for the specified action on the specified + * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is + * attempting a direct access use Authorizable.authorize(). + * + * @param authorizer authorizer + * @param action action + * @param user user + * @return is authorized + */ + default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user) { // TODO - include user details context // build the request final AuthorizationRequest request = new AuthorizationRequest.Builder() - .identity(user.getIdentity()) - .anonymous(user.isAnonymous()) - .accessAttempt(false) - .action(action) - .resource(getResource()) - .build(); + .identity(user.getIdentity()) + .anonymous(user.isAnonymous()) + .accessAttempt(false) + .action(action) + .resource(getResource()) + .build(); // perform the authorization final AuthorizationResult result = authorizer.authorize(request); 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 92d8e332ba..0454ad73ca 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 @@ -169,6 +169,18 @@ public final class ResourceFactory { } }; + private final static Resource COUNTERS_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return ResourceType.Counters.getValue(); + } + + @Override + public String getName() { + return "Counters"; + } + }; + private final static Resource PROVENANCE_RESOURCE = new Resource() { @Override public String getIdentifier() { @@ -436,6 +448,15 @@ public final class ResourceFactory { return PROCESS_GROUP_RESOURCE; } + /** + * Gets the Resource for accessing the Counters.. + * + * @return The resource for accessing the Controller + */ + public static Resource getCountersResource() { + return COUNTERS_RESOURCE; + } + /** * Gets the Resource for accessing provenance. Access to this Resource allows the user to access data provenance. However, additional authorization * is required based on the component that generated the event and the attributes of the event. @@ -528,6 +549,29 @@ public final class ResourceFactory { return USER_RESOURCE; } + /** + * Gets a Resource for performing site to site on a port. + * + * @param identifier The identifier of the component being accessed + * @param name The name of the component being accessed + * @return The resource + */ + public static Resource getSiteToSiteResource(final String identifier, final String name) { + Objects.requireNonNull(identifier, "The component identifier must be specified."); + + return new Resource() { + @Override + public String getIdentifier() { + return String.format("%s/%s", ResourceType.SiteToSite.getValue(), identifier); + } + + @Override + public String getName() { + return name; + } + }; + } + /** * Gets the {@link Resource} for accessing {@link AccessPolicy}s. * @return The policies resource 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 784af6dd17..94b61181ef 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 @@ -38,6 +38,7 @@ public enum ResourceType { System("/system"), Template("/templates"), Token("/token"), + Counters("/counters"), User("/users"); final String value; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java index 80e740625f..f560cd768b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java @@ -35,10 +35,6 @@ public class NiFiUser implements Serializable { this(identity, identity, null); } - public NiFiUser(String identity, String userName) { - this(identity, userName, null); - } - public NiFiUser(String identity, NiFiUser chain) { this(identity, identity, chain); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ReportingTasksEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ReportingTasksEndpointMerger.java index a5390e861f..8771722192 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ReportingTasksEndpointMerger.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ReportingTasksEndpointMerger.java @@ -30,7 +30,7 @@ import java.util.Map; import java.util.Set; public class ReportingTasksEndpointMerger implements EndpointResponseMerger { - public static final String REPORTING_TASKS_URI = "/nifi-api/controller/reporting-tasks"; + public static final String REPORTING_TASKS_URI = "/nifi-api/flow/reporting-tasks"; @Override public boolean canHandle(URI uri, String method) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/web/revision/UpdateRevisionTask.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/web/revision/UpdateRevisionTask.java index f2f7914a18..bcf68b512b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/web/revision/UpdateRevisionTask.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/web/revision/UpdateRevisionTask.java @@ -17,12 +17,6 @@ package org.apache.nifi.web.revision; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.apache.nifi.web.Revision; - /** *

* A task that is responsible for updating some component(s). @@ -35,30 +29,4 @@ public interface UpdateRevisionTask { * @return the updated revisions for the components */ RevisionUpdate update(); - - /** - * Returns a new Revision that has the same Client ID and Component ID as the given one - * but with a larger version - * - * @param revision the revision to update - * @return the updated Revision - */ - default Revision incrementRevision(Revision revision) { - return new Revision(revision.getVersion() + 1, revision.getClientId(), revision.getComponentId()); - } - - /** - * Returns a Collection of Revisions that contains an updated version of all Revisions passed in - * - * @param revisions the Revisions to update - * @return a Collection of all Revisions that are passed in - */ - default Collection incrementRevisions(Revision... revisions) { - final List updated = new ArrayList<>(revisions.length); - for (final Revision revision : revisions) { - updated.add(incrementRevision(revision)); - } - - return updated; - } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java index b2d920aeb6..9dd9762657 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java @@ -16,14 +16,7 @@ */ package org.apache.nifi.controller; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - +import org.apache.commons.io.IOUtils; import org.apache.nifi.admin.service.AuditService; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.cluster.protocol.StandardDataFlow; @@ -31,6 +24,8 @@ import org.apache.nifi.controller.repository.FlowFileEventRepository; import org.apache.nifi.controller.serialization.FlowSerializationException; import org.apache.nifi.controller.serialization.FlowSerializer; import org.apache.nifi.controller.serialization.StandardFlowSerializer; +import org.apache.nifi.encrypt.StringEncryptor; +import org.apache.nifi.events.VolatileBulletinRepository; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.web.api.dto.ConnectableDTO; import org.apache.nifi.web.api.dto.ConnectionDTO; @@ -41,15 +36,20 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.ProcessorConfigDTO; import org.apache.nifi.web.api.dto.ProcessorDTO; import org.apache.nifi.web.revision.RevisionManager; -import org.apache.commons.io.IOUtils; -import org.apache.nifi.encrypt.StringEncryptor; -import org.apache.nifi.events.VolatileBulletinRepository; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + /** */ @Ignore diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java index 16f47845d1..0933013075 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java @@ -16,27 +16,6 @@ */ package org.apache.nifi.controller.scheduling; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.io.File; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - import org.apache.commons.io.FileUtils; import org.apache.nifi.admin.service.AuditService; import org.apache.nifi.annotation.lifecycle.OnScheduled; @@ -71,6 +50,27 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + /** * Validate Processor's life-cycle operation within the context of * {@link FlowController} and {@link StandardProcessScheduler} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRootGroupPort.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRootGroupPort.java index cd10d5ca7a..9ad9987d3a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRootGroupPort.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRootGroupPort.java @@ -16,7 +16,14 @@ */ package org.apache.nifi.remote; +import org.apache.nifi.authorization.AuthorizationResult; +import org.apache.nifi.authorization.AuthorizationResult.Result; import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.resource.Authorizable; +import org.apache.nifi.authorization.resource.ResourceFactory; +import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.components.ValidationResult; import org.apache.nifi.connectable.ConnectableType; import org.apache.nifi.controller.AbstractPort; @@ -72,6 +79,7 @@ public class StandardRootGroupPort extends AbstractPort implements RootGroupPort private final ProcessScheduler processScheduler; private final boolean secure; private final Authorizer authorizer; + @SuppressWarnings("unused") private final BulletinRepository bulletinRepository; private final EventReporter eventReporter; @@ -336,6 +344,16 @@ public class StandardRootGroupPort extends AbstractPort implements RootGroupPort } } + @Override + public Authorizable getParentAuthorizable() { + return null; + } + + @Override + public Resource getResource() { + return ResourceFactory.getSiteToSiteResource(getIdentifier(), getName()); + } + @Override public PortAuthorizationResult checkUserAuthorization(final String dn) { if (!secure) { @@ -349,7 +367,15 @@ public class StandardRootGroupPort extends AbstractPort implements RootGroupPort return new StandardPortAuthorizationResult(false, "User DN is not known"); } - // TODO - Replace with call to Authorizer to authorize site to site data transfer + // attempt to authorize the specified user + final AuthorizationResult result = checkAuthorization(authorizer, RequestAction.WRITE, new NiFiUser(dn)); + if (!Result.Approved.equals(result.getResult())) { + final String message = String.format("%s authorization failed for user %s because %s", this, dn, result.getExplanation()); + logger.warn(message); + eventReporter.reportEvent(Severity.WARNING, CATEGORY, message); + return new StandardPortAuthorizationResult(false, message); + } + return new StandardPortAuthorizationResult(true, "User is Authorized"); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletConfigurationRequestContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletConfigurationRequestContext.java index 986ce4cbc4..7c4131ff78 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletConfigurationRequestContext.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletConfigurationRequestContext.java @@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest; */ public class HttpServletConfigurationRequestContext extends HttpServletRequestContext implements NiFiWebConfigurationRequestContext { + private static final String ID_PARAM = "id"; private static final String CLIENT_ID_PARAM = "clientId"; private static final String REVISION_PARAM = "revision"; @@ -36,7 +37,7 @@ public class HttpServletConfigurationRequestContext extends HttpServletRequestCo /** * @return the revision retrieved from the request parameters with keys - * equal to "clientId" and "revision". + * equal to "clientId", "revision", and "id". */ @Override public Revision getRevision() { @@ -49,8 +50,9 @@ public class HttpServletConfigurationRequestContext extends HttpServletRequestCo } final String clientId = request.getParameter(CLIENT_ID_PARAM); + final String componentId = request.getParameter(ID_PARAM); - return new Revision(revision, clientId); + return new Revision(revision, clientId, componentId); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml index 98824865ea..38ce1a627a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml @@ -49,7 +49,7 @@ org.apache.maven.plugins - maven-surefire-plugin + maven-failsafe-plugin -Xms512m -Xmx512m 1 diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/AuthorizableLookup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/AuthorizableLookup.java index e03271813f..f98878082f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/AuthorizableLookup.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/AuthorizableLookup.java @@ -24,6 +24,13 @@ import org.apache.nifi.controller.Snippet; public interface AuthorizableLookup { + /** + * Get the authorizable Controller. + * + * @return authorizable + */ + Authorizable getController(); + /** * Get the authorizable Processor. * diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java index f9a91cf432..1c08f7529d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java @@ -73,6 +73,7 @@ import org.apache.nifi.web.api.entity.ConnectionEntity; import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity; +import org.apache.nifi.web.api.entity.FlowConfigurationEntity; import org.apache.nifi.web.api.entity.FlowEntity; import org.apache.nifi.web.api.entity.FunnelEntity; import org.apache.nifi.web.api.entity.LabelEntity; @@ -289,6 +290,13 @@ public interface NiFiServiceFacade { */ ControllerConfigurationEntity getControllerConfiguration(); + /** + * Gets the configuration for the flow. + * + * @return Flow configuration transfer object + */ + FlowConfigurationEntity getFlowConfiguration(); + /** * Updates the configuration for this controller. * @@ -447,11 +455,12 @@ public interface NiFiServiceFacade { /** * Creates a new Processor. * + * @param revision revision * @param groupId Group id * @param processorDTO The processor DTO * @return The new processor DTO */ - ProcessorEntity createProcessor(String groupId, ProcessorDTO processorDTO); + ProcessorEntity createProcessor(Revision revision, String groupId, ProcessorDTO processorDTO); /** * Gets the Processor transfer object for the specified id. @@ -508,7 +517,7 @@ public interface NiFiServiceFacade { * @param processorDTO The processorDTO * @return The updated processor */ - UpdateResult updateProcessor(Revision revision, ProcessorDTO processorDTO); + ProcessorEntity updateProcessor(Revision revision, ProcessorDTO processorDTO); /** * Verifies the specified processor can be removed. @@ -565,11 +574,12 @@ public interface NiFiServiceFacade { /** * Creates a new Relationship target. * + * @param revision revision * @param groupId group * @param connectionDTO The Connection DTO * @return The Connection DTO */ - ConnectionEntity createConnection(String groupId, ConnectionDTO connectionDTO); + ConnectionEntity createConnection(Revision revision, String groupId, ConnectionDTO connectionDTO); /** * Determines if this connection can be listed. @@ -600,7 +610,7 @@ public interface NiFiServiceFacade { * @param connectionDTO The Connection DTO * @return The Connection DTO */ - UpdateResult updateConnection(Revision revision, ConnectionDTO connectionDTO); + ConnectionEntity updateConnection(Revision revision, ConnectionDTO connectionDTO); /** * Determines if this connection can be removed. @@ -690,11 +700,12 @@ public interface NiFiServiceFacade { /** * Creates a new input port. * + * @param revision revision * @param groupId The id of the group this port should be create in * @param inputPortDTO The input PortDTO * @return snapshot */ - PortEntity createInputPort(String groupId, PortDTO inputPortDTO); + PortEntity createInputPort(Revision revision, String groupId, PortDTO inputPortDTO); /** * Gets an input port. @@ -732,9 +743,9 @@ public interface NiFiServiceFacade { * * @param revision Revision to compare with current base revision * @param inputPortDTO The input PortDTO - * @return snapshort + * @return snapshot */ - UpdateResult updateInputPort(Revision revision, PortDTO inputPortDTO); + PortEntity updateInputPort(Revision revision, PortDTO inputPortDTO); /** * Determines if the input port could be deleted. @@ -758,11 +769,12 @@ public interface NiFiServiceFacade { /** * Creates a new output port. * + * @param revision revision * @param groupId The id of the group this port should be create in * @param outputPortDTO The output PortDTO * @return snapshot */ - PortEntity createOutputPort( String groupId, PortDTO outputPortDTO); + PortEntity createOutputPort(Revision revision, String groupId, PortDTO outputPortDTO); /** * Gets an output port. @@ -802,7 +814,7 @@ public interface NiFiServiceFacade { * @param outputPortDTO The output PortDTO * @return snapshot */ - UpdateResult updateOutputPort(Revision revision, PortDTO outputPortDTO); + PortEntity updateOutputPort(Revision revision, PortDTO outputPortDTO); /** * Determines if the output port could be deleted. @@ -838,11 +850,12 @@ public interface NiFiServiceFacade { /** * Creates a new process group. * + * @param revision revision * @param parentGroupId The id of the parent group * @param processGroupDTO The ProcessGroupDTO * @return snapshot */ - ProcessGroupEntity createProcessGroup(String parentGroupId, ProcessGroupDTO processGroupDTO); + ProcessGroupEntity createProcessGroup(Revision revision, String parentGroupId, ProcessGroupDTO processGroupDTO); /** * Returns the process group. @@ -886,7 +899,7 @@ public interface NiFiServiceFacade { * @param processGroupDTO The ProcessGroupDTO * @return snapshot */ - UpdateResult updateProcessGroup(Revision revision, ProcessGroupDTO processGroupDTO); + ProcessGroupEntity updateProcessGroup(Revision revision, ProcessGroupDTO processGroupDTO); /** * Verifies the specified process group can be removed. @@ -910,11 +923,12 @@ public interface NiFiServiceFacade { /** * Creates a new remote process group. * + * @param revision revision * @param groupId The id of the parent group * @param remoteProcessGroupDTO The RemoteProcessGroupDTO * @return snapshot */ - RemoteProcessGroupEntity createRemoteProcessGroup(String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO); + RemoteProcessGroupEntity createRemoteProcessGroup(Revision revision, String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO); /** * Gets a remote process group. @@ -978,7 +992,7 @@ public interface NiFiServiceFacade { * @param remoteProcessGroupDTO The RemoteProcessGroupDTO * @return snapshot */ - UpdateResult updateRemoteProcessGroup(Revision revision, RemoteProcessGroupDTO remoteProcessGroupDTO); + RemoteProcessGroupEntity updateRemoteProcessGroup(Revision revision, RemoteProcessGroupDTO remoteProcessGroupDTO); /** * Updates the specified remote process groups input port. @@ -1022,11 +1036,12 @@ public interface NiFiServiceFacade { /** * Creates a funnel. * + * @param revision revision * @param groupId group * @param funnelDTO funnel * @return The funnel DTO */ - FunnelEntity createFunnel(String groupId, FunnelDTO funnelDTO); + FunnelEntity createFunnel(Revision revision, String groupId, FunnelDTO funnelDTO); /** * Gets the specified funnel. @@ -1045,13 +1060,13 @@ public interface NiFiServiceFacade { Set getFunnels(String groupId); /** - * Updates the specified label. + * Updates the specified funnel. * * @param revision Revision to compare with current base revision * @param funnelDTO The funnel DTO * @return The funnel DTO */ - UpdateResult updateFunnel(Revision revision, FunnelDTO funnelDTO); + FunnelEntity updateFunnel(Revision revision, FunnelDTO funnelDTO); /** * Verifies the specified funnel can be deleted. @@ -1145,11 +1160,12 @@ public interface NiFiServiceFacade { /** * Creates a label. * + * @param revision revision * @param groupId group * @param labelDTO The label DTO * @return The label DTO */ - LabelEntity createLabel(String groupId, LabelDTO labelDTO); + LabelEntity createLabel(Revision revision, String groupId, LabelDTO labelDTO); /** * Gets the specified label. @@ -1174,7 +1190,7 @@ public interface NiFiServiceFacade { * @param labelDTO The label DTO * @return The label DTO */ - UpdateResult updateLabel(Revision revision, LabelDTO labelDTO); + LabelEntity updateLabel(Revision revision, LabelDTO labelDTO); /** * Deletes the specified label. @@ -1210,7 +1226,7 @@ public interface NiFiServiceFacade { * @param userDTO The user DTO * @return The user transfer object */ - UpdateResult updateUser(Revision revision, UserDTO userDTO); + UserEntity updateUser(Revision revision, UserDTO userDTO); /** * Deletes the specified user. @@ -1245,7 +1261,7 @@ public interface NiFiServiceFacade { * @param userGroupDTO The user group DTO * @return The user group transfer object */ - UpdateResult updateUserGroup(Revision revision, UserGroupDTO userGroupDTO); + UserGroupEntity updateUserGroup(Revision revision, UserGroupDTO userGroupDTO); /** * Deletes the specified user group. @@ -1279,7 +1295,7 @@ public interface NiFiServiceFacade { * @param accessPolicyDTO The access policy DTO * @return The access policy transfer object */ - UpdateResult updateAccessPolicy(Revision revision, AccessPolicyDTO accessPolicyDTO); + AccessPolicyEntity updateAccessPolicy(Revision revision, AccessPolicyDTO accessPolicyDTO); /** * Deletes the specified access policy. @@ -1295,11 +1311,12 @@ public interface NiFiServiceFacade { /** * Creates a controller service. * + * @param revision revision * @param groupId the ID of the Process Group to add the Controller Service to * @param controllerServiceDTO The controller service DTO * @return The controller service DTO */ - ControllerServiceEntity createControllerService(String groupId, ControllerServiceDTO controllerServiceDTO); + ControllerServiceEntity createControllerService(Revision revision, String groupId, ControllerServiceDTO controllerServiceDTO); /** * Gets all controller services that belong to the given group and its parent/ancestor groups @@ -1347,13 +1364,13 @@ public interface NiFiServiceFacade { Map referenceRevisions, String controllerServiceId, ScheduledState scheduledState, ControllerServiceState controllerServiceState); /** - * Updates the specified label. + * Updates the specified controller service. * * @param revision Revision to compare with current base revision * @param controllerServiceDTO The controller service DTO * @return The controller service DTO */ - UpdateResult updateControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO); + ControllerServiceEntity updateControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO); /** * Deletes the specified label. @@ -1393,10 +1410,11 @@ public interface NiFiServiceFacade { /** * Creates a reporting task. * + * @param revision revision * @param reportingTaskDTO The reporting task DTO * @return The reporting task DTO */ - ReportingTaskEntity createReportingTask(ReportingTaskDTO reportingTaskDTO); + ReportingTaskEntity createReportingTask(Revision revision, ReportingTaskDTO reportingTaskDTO); /** * Gets all reporting tasks. @@ -1429,7 +1447,7 @@ public interface NiFiServiceFacade { * @param reportingTaskDTO The reporting task DTO * @return The reporting task DTO */ - UpdateResult updateReportingTask(Revision revision, ReportingTaskDTO reportingTaskDTO); + ReportingTaskEntity updateReportingTask(Revision revision, ReportingTaskDTO reportingTaskDTO); /** * Deletes the specified reporting task. diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardAuthorizableLookup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardAuthorizableLookup.java index aef2798d6b..f702ffc6cc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardAuthorizableLookup.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardAuthorizableLookup.java @@ -66,6 +66,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup { private TemplateDAO templateDAO; private AccessPolicyDAO accessPolicyDAO; + @Override + public Authorizable getController() { + return controllerFacade; + } + @Override public Authorizable getProcessor(final String id) { return processorDAO.getProcessor(id); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index 50fa50553c..eaaef986bb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -17,15 +17,16 @@ package org.apache.nifi.web; import com.google.common.collect.Sets; -import org.apache.commons.lang3.StringUtils; import org.apache.nifi.action.Action; import org.apache.nifi.action.Component; import org.apache.nifi.action.FlowChangeAction; import org.apache.nifi.action.Operation; import org.apache.nifi.action.details.FlowChangePurgeDetails; import org.apache.nifi.admin.service.AuditService; -import org.apache.nifi.admin.service.KeyService; +import org.apache.nifi.authorization.AccessDeniedException; import org.apache.nifi.authorization.AccessPolicy; +import org.apache.nifi.authorization.AuthorizationResult; +import org.apache.nifi.authorization.AuthorizationResult.Result; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.Group; import org.apache.nifi.authorization.RequestAction; @@ -97,6 +98,7 @@ import org.apache.nifi.web.api.dto.DocumentedTypeDTO; import org.apache.nifi.web.api.dto.DropRequestDTO; import org.apache.nifi.web.api.dto.DtoFactory; import org.apache.nifi.web.api.dto.EntityFactory; +import org.apache.nifi.web.api.dto.FlowConfigurationDTO; import org.apache.nifi.web.api.dto.FlowFileDTO; import org.apache.nifi.web.api.dto.FlowSnippetDTO; import org.apache.nifi.web.api.dto.FunnelDTO; @@ -141,6 +143,7 @@ import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity; +import org.apache.nifi.web.api.entity.FlowConfigurationEntity; import org.apache.nifi.web.api.entity.FlowEntity; import org.apache.nifi.web.api.entity.FunnelEntity; import org.apache.nifi.web.api.entity.LabelEntity; @@ -184,6 +187,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -240,7 +244,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { // administrative services private AuditService auditService; - private KeyService keyService; // properties private NiFiProperties properties; @@ -515,12 +518,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { // Write Operations // ----------------------------------------- @Override - public UpdateResult updateAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) { - // if access policy does not exist, then create new access policy - if (!accessPolicyDAO.hasAccessPolicy(accessPolicyDTO.getId())) { - return new UpdateResult<>(createAccessPolicy(revision, accessPolicyDTO), false); - } - + public AccessPolicyEntity updateAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) { final Authorizable accessPolicyAuthorizable = authorizableLookup.getAccessPolicyAuthorizable(accessPolicyDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, accessPolicyAuthorizable, @@ -532,16 +530,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { }); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(accessPolicyAuthorizable); - return new UpdateResult<>(entityFactory.createAccessPolicyEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false); + return entityFactory.createAccessPolicyEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy); } @Override - public UpdateResult updateUser(final Revision revision, final UserDTO userDTO) { - // if user does not exist, then create new user - if (!userDAO.hasUser(userDTO.getId())) { - return new UpdateResult<>(createUser(revision, userDTO), false); - } - + public UserEntity updateUser(final Revision revision, final UserDTO userDTO) { final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable(); final RevisionUpdate snapshot = updateComponent(revision, usersAuthorizable, @@ -549,16 +542,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { user -> dtoFactory.createUserDto(user, user.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()))); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable); - return new UpdateResult<>(entityFactory.createUserEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false); + return entityFactory.createUserEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy); } @Override - public UpdateResult updateUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) { - // if user group does not exist, then create new user group - if (!userGroupDAO.hasUserGroup(userGroupDTO.getId())) { - return new UpdateResult<>(createUserGroup(revision, userGroupDTO), false); - } - + public UserGroupEntity updateUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) { final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable(); final RevisionUpdate snapshot = updateComponent(revision, userGroupsAuthorizable, @@ -566,16 +554,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { userGroup -> dtoFactory.createUserGroupDto(userGroup, userGroup.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()))); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable); - return new UpdateResult<>(entityFactory.createUserGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false); + return entityFactory.createUserGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy); } @Override - public UpdateResult updateConnection(final Revision revision, final ConnectionDTO connectionDTO) { - // if connection does not exist, then create new connection - if (connectionDAO.hasConnection(connectionDTO.getId()) == false) { - return new UpdateResult<>(createConnection(connectionDTO.getParentGroupId(), connectionDTO), true); - } - + public ConnectionEntity updateConnection(final Revision revision, final ConnectionDTO connectionDTO) { final Connection connectionNode = connectionDAO.getConnection(connectionDTO.getId()); final RevisionUpdate snapshot = updateComponent( @@ -586,16 +569,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(connectionNode); final ConnectionStatusDTO status = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connectionNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createConnectionEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status), false); + return entityFactory.createConnectionEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status); } @Override - public UpdateResult updateProcessor(final Revision revision, final ProcessorDTO processorDTO) { - // if processor does not exist, then create new processor - if (processorDAO.hasProcessor(processorDTO.getId()) == false) { - return new UpdateResult<>(createProcessor(processorDTO.getParentGroupId(), processorDTO), true); - } - + public ProcessorEntity updateProcessor(final Revision revision, final ProcessorDTO processorDTO) { // get the component, ensure we have access to it, and perform the update request final ProcessorNode processorNode = processorDAO.getProcessor(processorDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, @@ -606,16 +584,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(processorNode); final ProcessorStatusDTO status = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(processorNode.getIdentifier())); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processorNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createProcessorEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins), false); + return entityFactory.createProcessorEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins); } @Override - public UpdateResult updateLabel(final Revision revision, final LabelDTO labelDTO) { - // if label does not exist, then create new label - if (labelDAO.hasLabel(labelDTO.getId()) == false) { - return new UpdateResult<>(createLabel(labelDTO.getParentGroupId(), labelDTO), false); - } - + public LabelEntity updateLabel(final Revision revision, final LabelDTO labelDTO) { final Label labelNode = labelDAO.getLabel(labelDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, labelNode, @@ -623,16 +596,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { label -> dtoFactory.createLabelDto(label)); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(labelNode); - return new UpdateResult<>(entityFactory.createLabelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false); + return entityFactory.createLabelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy); } @Override - public UpdateResult updateFunnel(final Revision revision, final FunnelDTO funnelDTO) { - // if label does not exist, then create new label - if (funnelDAO.hasFunnel(funnelDTO.getId()) == false) { - return new UpdateResult<>(createFunnel(funnelDTO.getParentGroupId(), funnelDTO), true); - } - + public FunnelEntity updateFunnel(final Revision revision, final FunnelDTO funnelDTO) { final Funnel funnelNode = funnelDAO.getFunnel(funnelDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, funnelNode, @@ -640,7 +608,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { funnel -> dtoFactory.createFunnelDto(funnel)); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(funnelNode); - return new UpdateResult<>(entityFactory.createFunnelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy), false); + return entityFactory.createFunnelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy); } @@ -657,7 +625,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { */ private RevisionUpdate updateComponent(final Revision revision, final Authorizable authorizable, final Supplier daoUpdate, final Function dtoCreation) { final NiFiUser user = NiFiUserUtils.getNiFiUser(); - final String userName = NiFiUserUtils.getNiFiUserName(); try { final RevisionUpdate updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(revision), user, new UpdateRevisionTask() { @Override @@ -668,10 +635,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { // save updated controller controllerFacade.save(); - final Revision updatedRevision = incrementRevision(revision); final D dto = dtoCreation.apply(component); - final FlowModification lastModification = new FlowModification(updatedRevision, userName); + final Revision updatedRevision = revisionManager.getRevision(revision.getComponentId()).incrementRevision(revision.getClientId()); + final FlowModification lastModification = new FlowModification(updatedRevision, user.getUserName()); return new StandardRevisionUpdate<>(dto, lastModification); } }); @@ -717,7 +684,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { controllerFacade.save(); // increment the revisions - final Set updatedRevisions = revisions.stream().map(revision -> incrementRevision(revision)).collect(Collectors.toSet()); + final Set updatedRevisions = revisions.stream().map(revision -> { + final Revision currentRevision = revisionManager.getRevision(revision.getComponentId()); + return currentRevision.incrementRevision(revision.getClientId()); + }).collect(Collectors.toSet()); final SnippetDTO dto = dtoFactory.createSnippetDto(snippet); return new StandardRevisionUpdate<>(dto, null, updatedRevisions); @@ -731,12 +701,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public UpdateResult updateInputPort(final Revision revision, final PortDTO inputPortDTO) { - // if input port does not exist, then create new input port - if (inputPortDAO.hasPort(inputPortDTO.getId()) == false) { - return new UpdateResult<>(createInputPort(inputPortDTO.getParentGroupId(), inputPortDTO), true); - } - + public PortEntity updateInputPort(final Revision revision, final PortDTO inputPortDTO) { final Port inputPortNode = inputPortDAO.getPort(inputPortDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, inputPortNode, @@ -746,16 +711,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(inputPortNode); final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getInputPortStatus(inputPortNode.getIdentifier())); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(inputPortNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins), false); + return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins); } @Override - public UpdateResult updateOutputPort(final Revision revision, final PortDTO outputPortDTO) { - // if output port does not exist, then create new output port - if (outputPortDAO.hasPort(outputPortDTO.getId()) == false) { - return new UpdateResult<>(createOutputPort(outputPortDTO.getParentGroupId(), outputPortDTO), true); - } - + public PortEntity updateOutputPort(final Revision revision, final PortDTO outputPortDTO) { final Port outputPortNode = outputPortDAO.getPort(outputPortDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, outputPortNode, @@ -765,16 +725,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(outputPortNode); final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getOutputPortStatus(outputPortNode.getIdentifier())); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(outputPortNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins), false); + return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, status, bulletins); } @Override - public UpdateResult updateRemoteProcessGroup(final Revision revision, final RemoteProcessGroupDTO remoteProcessGroupDTO) { - // if controller reference does not exist, then create new controller reference - if (remoteProcessGroupDAO.hasRemoteProcessGroup(remoteProcessGroupDTO.getId()) == false) { - return new UpdateResult<>(createRemoteProcessGroup(remoteProcessGroupDTO.getParentGroupId(), remoteProcessGroupDTO), true); - } - + public RemoteProcessGroupEntity updateRemoteProcessGroup(final Revision revision, final RemoteProcessGroupDTO remoteProcessGroupDTO) { final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId()); final RevisionUpdate snapshot = updateComponent( revision, @@ -786,7 +741,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification()); final RemoteProcessGroupStatusDTO status = dtoFactory.createRemoteProcessGroupStatusDto(controllerFacade.getRemoteProcessGroupStatus(remoteProcessGroupNode.getIdentifier())); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(remoteProcessGroupNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createRemoteProcessGroupEntity(snapshot.getComponent(), updateRevision, accessPolicy, status, bulletins), false); + return entityFactory.createRemoteProcessGroupEntity(snapshot.getComponent(), updateRevision, accessPolicy, status, bulletins); } @Override @@ -822,16 +777,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public UpdateResult updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) { - // if process group does not exist, then create new process group - if (processGroupDAO.hasProcessGroup(processGroupDTO.getId()) == false) { - if (processGroupDTO.getParentGroupId() == null) { - throw new IllegalArgumentException("Unable to create the specified process group since the parent group was not specified."); - } else { - return new UpdateResult<>(createProcessGroup(processGroupDTO.getParentGroupId(), processGroupDTO), true); - } - } - + public ProcessGroupEntity updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) { final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(processGroupDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, processGroupNode, @@ -842,7 +788,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification()); final ProcessGroupStatusDTO status = dtoFactory.createConciseProcessGroupStatusDto(controllerFacade.getProcessGroupStatus(processGroupNode.getIdentifier())); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processGroupNode.getIdentifier())); - return new UpdateResult<>(entityFactory.createProcessGroupEntity(snapshot.getComponent(), updatedRevision, accessPolicy, status, bulletins), false); + return entityFactory.createProcessGroupEntity(snapshot.getComponent(), updatedRevision, accessPolicy, status, bulletins); } @Override @@ -859,8 +805,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final Map updatedRevisions = new HashMap<>(); for (final Revision revision : componentRevisions.values()) { final Revision currentRevision = revisionManager.getRevision(revision.getComponentId()); - final Revision updatedRevision = incrementRevision(currentRevision); - updatedRevisions.put(revision.getComponentId(), updatedRevision); + updatedRevisions.put(revision.getComponentId(), currentRevision.incrementRevision(revision.getClientId())); } // gather details for response @@ -887,9 +832,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount()); } - return controllerConfigurationDTO; - }, - controller -> dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval())); + return controllerConfigurationDTO; + }, + controller -> dtoFactory.createControllerConfigurationDto(controllerFacade)); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerFacade); final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(updatedComponent.getLastModification()); @@ -991,17 +936,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public DropRequestDTO deleteFlowFileDropRequest(final String connectionId, final String dropRequestId) { - final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); - return dtoFactory.createDropRequestDTO(connectionDAO.deleteFlowFileDropRequest(connectionId, dropRequestId)); } @Override public ListingRequestDTO deleteFlowFileListingRequest(final String connectionId, final String listingRequestId) { final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); - final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.deleteFlowFileListingRequest(connectionId, listingRequestId)); // include whether the source and destination are running @@ -1211,8 +1151,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ConnectionEntity createConnection(final String groupId, final ConnectionDTO connectionDTO) { + public ConnectionEntity createConnection(final Revision revision, final String groupId, final ConnectionDTO connectionDTO) { final RevisionUpdate snapshot = createComponent( + revision, connectionDTO, () -> connectionDAO.createConnection(groupId, connectionDTO), connection -> dtoFactory.createConnectionDto(connection)); @@ -1225,17 +1166,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public DropRequestDTO createFlowFileDropRequest(final String connectionId, final String dropRequestId) { - final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); return dtoFactory.createDropRequestDTO(connectionDAO.createFlowFileDropRequest(connectionId, dropRequestId)); } @Override public ListingRequestDTO createFlowFileListingRequest(final String connectionId, final String listingRequestId) { final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); - - // create the listing request final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.createFlowFileListingRequest(connectionId, listingRequestId)); // include whether the source and destination are running @@ -1250,8 +1186,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ProcessorEntity createProcessor(final String groupId, final ProcessorDTO processorDTO) { + public ProcessorEntity createProcessor(final Revision revision, final String groupId, final ProcessorDTO processorDTO) { final RevisionUpdate snapshot = createComponent( + revision, processorDTO, () -> processorDAO.createProcessor(groupId, processorDTO), processor -> dtoFactory.createProcessorDto(processor)); @@ -1264,8 +1201,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public LabelEntity createLabel(final String groupId, final LabelDTO labelDTO) { + public LabelEntity createLabel(final Revision revision, final String groupId, final LabelDTO labelDTO) { final RevisionUpdate snapshot = createComponent( + revision, labelDTO, () -> labelDAO.createLabel(groupId, labelDTO), label -> dtoFactory.createLabelDto(label)); @@ -1285,32 +1223,39 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { * @param the NiFi Component Type * @return a RevisionUpdate that represents the updated configuration */ - private RevisionUpdate createComponent(final ComponentDTO componentDto, final Supplier daoCreation, final Function dtoCreation) { - final String modifier = NiFiUserUtils.getNiFiUserName(); - - // ensure id is set - if (StringUtils.isBlank(componentDto.getId())) { - componentDto.setId(UUID.randomUUID().toString()); - } - + private RevisionUpdate createComponent(final Revision revision, final ComponentDTO componentDto, final Supplier daoCreation, final Function dtoCreation) { + final NiFiUser user = NiFiUserUtils.getNiFiUser(); final String groupId = componentDto.getParentGroupId(); + + // read lock on the containing group return revisionManager.get(groupId, rev -> { - // add the component - final C component = daoCreation.get(); + // request claim for component to be created... revision already verified (version == 0) + final RevisionClaim claim = revisionManager.requestClaim(revision, user); + try { + // update revision through revision manager + return revisionManager.updateRevision(claim, user, () -> { + // add the component + final C component = daoCreation.get(); - // save the flow - controllerFacade.save(); + // save the flow + controllerFacade.save(); - final D dto = dtoCreation.apply(component); - final FlowModification lastMod = new FlowModification(new Revision(0L, rev.getClientId(), componentDto.getId()), modifier); - return new StandardRevisionUpdate(dto, lastMod); + final D dto = dtoCreation.apply(component); + final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getUserName()); + return new StandardRevisionUpdate(dto, lastMod); + }); + } finally { + // cancel in case of exception... noop if successful + revisionManager.cancelClaim(revision.getComponentId()); + } }); } @Override - public FunnelEntity createFunnel(final String groupId, final FunnelDTO funnelDTO) { + public FunnelEntity createFunnel(final Revision revision, final String groupId, final FunnelDTO funnelDTO) { final RevisionUpdate snapshot = createComponent( + revision, funnelDTO, () -> funnelDAO.createFunnel(groupId, funnelDTO), funnel -> dtoFactory.createFunnelDto(funnel)); @@ -1323,9 +1268,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public AccessPolicyEntity createAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) { final String creator = NiFiUserUtils.getNiFiUserName(); - if (revision.getVersion() != 0) { - throw new IllegalArgumentException("The revision must start at 0."); - } final AccessPolicy newAccessPolicy = accessPolicyDAO.createAccessPolicy(accessPolicyDTO); final AccessPolicyDTO newAccessPolicyDto = dtoFactory.createAccessPolicyDto(newAccessPolicy, newAccessPolicy.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()), @@ -1338,9 +1280,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public UserEntity createUser(final Revision revision, final UserDTO userDTO) { final String creator = NiFiUserUtils.getNiFiUserName(); - if (revision.getVersion() != 0) { - throw new IllegalArgumentException("The revision must start at 0."); - } final User newUser = userDAO.createUser(userDTO); final UserDTO newUserDto = dtoFactory.createUserDto(newUser, newUser.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet())); @@ -1458,8 +1397,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public PortEntity createInputPort(final String groupId, final PortDTO inputPortDTO) { + public PortEntity createInputPort(final Revision revision, final String groupId, final PortDTO inputPortDTO) { final RevisionUpdate snapshot = createComponent( + revision, inputPortDTO, () -> inputPortDAO.createPort(groupId, inputPortDTO), port -> dtoFactory.createPortDto(port)); @@ -1472,8 +1412,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public PortEntity createOutputPort(final String groupId, final PortDTO outputPortDTO) { + public PortEntity createOutputPort(final Revision revision, final String groupId, final PortDTO outputPortDTO) { final RevisionUpdate snapshot = createComponent( + revision, outputPortDTO, () -> outputPortDAO.createPort(groupId, outputPortDTO), port -> dtoFactory.createPortDto(port)); @@ -1486,8 +1427,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ProcessGroupEntity createProcessGroup(final String parentGroupId, final ProcessGroupDTO processGroupDTO) { + public ProcessGroupEntity createProcessGroup(final Revision revision, final String parentGroupId, final ProcessGroupDTO processGroupDTO) { final RevisionUpdate snapshot = createComponent( + revision, processGroupDTO, () -> processGroupDAO.createProcessGroup(parentGroupId, processGroupDTO), processGroup -> dtoFactory.createProcessGroupDto(processGroup)); @@ -1500,8 +1442,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public RemoteProcessGroupEntity createRemoteProcessGroup(final String groupId, final RemoteProcessGroupDTO remoteProcessGroupDTO) { + public RemoteProcessGroupEntity createRemoteProcessGroup(final Revision revision, final String groupId, final RemoteProcessGroupDTO remoteProcessGroupDTO) { final RevisionUpdate snapshot = createComponent( + revision, remoteProcessGroupDTO, () -> remoteProcessGroupDAO.createRemoteProcessGroup(groupId, remoteProcessGroupDTO), remoteProcessGroup -> dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup)); @@ -1639,49 +1582,60 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ControllerServiceEntity createControllerService(final String groupId, final ControllerServiceDTO controllerServiceDTO) { + public ControllerServiceEntity createControllerService(final Revision revision, final String groupId, final ControllerServiceDTO controllerServiceDTO) { controllerServiceDTO.setParentGroupId(groupId); - final String modifier = NiFiUserUtils.getNiFiUserName(); + final NiFiUser user = NiFiUserUtils.getNiFiUser(); - // ensure id is set - if (StringUtils.isBlank(controllerServiceDTO.getId())) { - controllerServiceDTO.setId(UUID.randomUUID().toString()); - } + // request claim for component to be created... revision already verified (version == 0) + final RevisionClaim claim = revisionManager.requestClaim(revision, user); - final ControllerServiceDTO updatedService; + final RevisionUpdate snapshot; if (groupId == null) { - // Unfortunately, we can not use the createComponent() method here because createComponent() wants to obtain the read lock - // on the group. The Controller Service may or may not have a Process Group (it won't if it's controller-scoped). - final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO); - updatedService = dtoFactory.createControllerServiceDto(controllerService); - controllerFacade.save(); - } else { - updatedService = revisionManager.get(groupId, new ReadOnlyRevisionCallback() { - @Override - public ControllerServiceDTO withRevision(final Revision groupRevision) { + try { + // update revision through revision manager + snapshot = revisionManager.updateRevision(claim, user, () -> { + // Unfortunately, we can not use the createComponent() method here because createComponent() wants to obtain the read lock + // on the group. The Controller Service may or may not have a Process Group (it won't if it's controller-scoped). final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO); + final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(controllerService); + controllerFacade.save(); - return dtoFactory.createControllerServiceDto(controllerService); + + final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getUserName()); + return new StandardRevisionUpdate(dto, lastMod); + }); + } finally { + // cancel in case of exception... noop if successful + revisionManager.cancelClaim(revision.getComponentId()); + } + } else { + snapshot = revisionManager.get(groupId, groupRevision -> { + try { + return revisionManager.updateRevision(claim, user, () -> { + final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO); + final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(controllerService); + + controllerFacade.save(); + + final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getUserName()); + return new StandardRevisionUpdate(dto, lastMod); + }); + } finally { + // cancel in case of exception... noop if successful + revisionManager.cancelClaim(revision.getComponentId()); } }); } - final FlowModification lastMod = new FlowModification(new Revision(0L, null, controllerServiceDTO.getId()), modifier); - final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceDTO.getId()); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerService); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(controllerServiceDTO.getId())); - return entityFactory.createControllerServiceEntity(updatedService, dtoFactory.createRevisionDTO(lastMod), accessPolicy, bulletins); + return entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins); } @Override - public UpdateResult updateControllerService(final Revision revision, final ControllerServiceDTO controllerServiceDTO) { - // if controller service does not exist, then create new controller service - if (controllerServiceDAO.hasControllerService(controllerServiceDTO.getId()) == false) { - return new UpdateResult<>(createControllerService(controllerServiceDTO.getParentGroupId(), controllerServiceDTO), true); - } - + public ControllerServiceEntity updateControllerService(final Revision revision, final ControllerServiceDTO controllerServiceDTO) { // get the component, ensure we have access to it, and perform the update request final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, @@ -1691,7 +1645,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerService); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(controllerServiceDTO.getId())); - return new UpdateResult<>(entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins), false); + return entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins); } @Override @@ -1705,27 +1659,14 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { new UpdateRevisionTask() { @Override public RevisionUpdate update() { - final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId); - final ControllerServiceReference reference = controllerService.getReferences(); - for (final ConfiguredComponent component : reference.getReferencingComponents()) { - if (component instanceof Authorizable) { - // ensure we can write the referencing components - ((Authorizable) component).authorize(authorizer, RequestAction.WRITE); - } - } - final Set updated = controllerServiceDAO.updateControllerServiceReferencingComponents(controllerServiceId, scheduledState, controllerServiceState); final ControllerServiceReference updatedReference = controllerServiceDAO.getControllerService(controllerServiceId).getReferences(); final Map updatedRevisions = new HashMap<>(); - for (final Revision refRevision : referenceRevisions.values()) { - updatedRevisions.put(refRevision.getComponentId(), refRevision); - } - for (final ConfiguredComponent component : updated) { final Revision currentRevision = revisionManager.getRevision(component.getIdentifier()); - final Revision updatedRevision = incrementRevision(currentRevision); - updatedRevisions.put(component.getIdentifier(), updatedRevision); + final Revision requestRevision = referenceRevisions.get(component.getIdentifier()); + updatedRevisions.put(component.getIdentifier(), currentRevision.incrementRevision(requestRevision.getClientId())); } final ControllerServiceReferencingComponentsEntity entity = createControllerServiceReferencingComponentsEntity(updatedReference, updatedRevisions); @@ -1858,39 +1799,37 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override - public ReportingTaskEntity createReportingTask(final ReportingTaskDTO reportingTaskDTO) { - final String modifier = NiFiUserUtils.getNiFiUserName(); + public ReportingTaskEntity createReportingTask(final Revision revision, final ReportingTaskDTO reportingTaskDTO) { + final NiFiUser user = NiFiUserUtils.getNiFiUser(); - // ensure id is set - if (StringUtils.isBlank(reportingTaskDTO.getId())) { - reportingTaskDTO.setId(UUID.randomUUID().toString()); - } + // request claim for component to be created... revision already verified (version == 0) + final RevisionClaim claim = revisionManager.requestClaim(revision, user); + try { + // update revision through revision manager + final RevisionUpdate snapshot = revisionManager.updateRevision(claim, user, () -> { + // create the reporting task + final ReportingTaskNode reportingTask = reportingTaskDAO.createReportingTask(reportingTaskDTO); - return revisionManager.get(controllerFacade.getInstanceId(), rev -> { - // ensure access to the controller - controllerFacade.authorize(authorizer, RequestAction.WRITE); + // save the update + controllerFacade.save(); - // create the reporting task - final ReportingTaskNode reportingTask = reportingTaskDAO.createReportingTask(reportingTaskDTO); + final ReportingTaskDTO dto = dtoFactory.createReportingTaskDto(reportingTask); + final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getUserName()); + return new StandardRevisionUpdate(dto, lastMod); + }); - // save the update - controllerFacade.save(); - - final ReportingTaskDTO dto = dtoFactory.createReportingTaskDto(reportingTask); - final FlowModification lastMod = new FlowModification(new Revision(0L, rev.getClientId(), dto.getId()), modifier); + final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskDTO.getId()); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(reportingTask); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(reportingTask.getIdentifier())); - return entityFactory.createReportingTaskEntity(dto, dtoFactory.createRevisionDTO(lastMod), accessPolicy, bulletins); - }); + return entityFactory.createReportingTaskEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins); + } finally { + // cancel in case of exception... noop if successful + revisionManager.cancelClaim(revision.getComponentId()); + } } @Override - public UpdateResult updateReportingTask(final Revision revision, final ReportingTaskDTO reportingTaskDTO) { - // if reporting task does not exist, then create new reporting task - if (reportingTaskDAO.hasReportingTask(reportingTaskDTO.getId()) == false) { - return new UpdateResult<>(createReportingTask(reportingTaskDTO), true); - } - + public ReportingTaskEntity updateReportingTask(final Revision revision, final ReportingTaskDTO reportingTaskDTO) { // get the component, ensure we have access to it, and perform the update request final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskDTO.getId()); final RevisionUpdate snapshot = updateComponent(revision, @@ -1900,7 +1839,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(reportingTask); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(reportingTask.getIdentifier())); - return new UpdateResult<>(entityFactory.createReportingTaskEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins), false); + return entityFactory.createReportingTaskEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy, bulletins); } @Override @@ -2079,9 +2018,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public Set getConnections(final String groupId) { return revisionManager.get(groupId, rev -> { - final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); - group.authorize(authorizer, RequestAction.READ); - final Set connections = connectionDAO.getConnections(groupId); final Set connectionIds = connections.stream().map(connection -> connection.getIdentifier()).collect(Collectors.toSet()); return revisionManager.get(connectionIds, () -> { @@ -2101,8 +2037,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { public ConnectionEntity getConnection(final String connectionId) { return revisionManager.get(connectionId, rev -> { final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(connection); final ConnectionStatusDTO status = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connectionId)); @@ -2112,16 +2046,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public DropRequestDTO getFlowFileDropRequest(final String connectionId, final String dropRequestId) { - final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); return dtoFactory.createDropRequestDTO(connectionDAO.getFlowFileDropRequest(connectionId, dropRequestId)); } @Override public ListingRequestDTO getFlowFileListingRequest(final String connectionId, final String listingRequestId) { final Connection connection = connectionDAO.getConnection(connectionId); - connection.authorize(authorizer, RequestAction.WRITE); - final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.getFlowFileListingRequest(connectionId, listingRequestId)); // include whether the source and destination are running @@ -2152,9 +2082,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public Set getProcessors(final String groupId) { - final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); - group.authorize(authorizer, RequestAction.READ); - final Set processors = processorDAO.getProcessors(groupId); final Set ids = processors.stream().map(proc -> proc.getIdentifier()).collect(Collectors.toSet()); return revisionManager.get(ids, () -> { @@ -2219,8 +2146,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { public ProcessorEntity getProcessor(final String id) { return revisionManager.get(id, rev -> { final ProcessorNode processor = processorDAO.getProcessor(id); - processor.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final ProcessorStatusDTO status = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(id)); final List bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(id)); @@ -2396,19 +2321,25 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public ControllerConfigurationEntity getControllerConfiguration() { return revisionManager.get(FlowController.class.getSimpleName(), rev -> { - final ControllerConfigurationDTO dto = dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval()); + final ControllerConfigurationDTO dto = dtoFactory.createControllerConfigurationDto(controllerFacade); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerFacade); final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); return entityFactory.createControllerConfigurationEntity(dto, revision, accessPolicy); }); } + @Override + public FlowConfigurationEntity getFlowConfiguration() { + final FlowConfigurationDTO dto = dtoFactory.createFlowConfigurationDto(properties.getAutoRefreshInterval()); + final FlowConfigurationEntity entity = new FlowConfigurationEntity(); + entity.setFlowConfiguration(dto); + return entity; + } + @Override public AccessPolicyEntity getAccessPolicy(final String accessPolicyId) { return revisionManager.get(accessPolicyId, rev -> { final Authorizable accessPolicyAuthorizable = authorizableLookup.getAccessPolicyAuthorizable(accessPolicyId); - accessPolicyAuthorizable.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(accessPolicyAuthorizable); final AccessPolicy requestedAccessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyId); @@ -2424,8 +2355,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { public UserEntity getUser(final String userId, final boolean prune) { return revisionManager.get(userId, rev -> { final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable(); - usersAuthorizable.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable); final User user = userDAO.getUser(userId); @@ -2439,8 +2368,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { private UserEntity getUserPruned(final String userId) { return revisionManager.get(userId, rev -> { final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable(); - usersAuthorizable.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable); final User user = userDAO.getUser(userId); @@ -2452,8 +2379,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { public UserGroupEntity getUserGroup(final String userGroupId, final boolean prune) { return revisionManager.get(userGroupId, rev -> { final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable(); - userGroupsAuthorizable.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable); final Group userGroup = userGroupDAO.getUserGroup(userGroupId); @@ -2466,8 +2391,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { private UserGroupEntity getUserGroupPruned(final String userGroupId) { return revisionManager.get(userGroupId, rev -> { final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable(); - userGroupsAuthorizable.authorize(authorizer, RequestAction.READ); - final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable); final Group userGroup = userGroupDAO.getUserGroup(userGroupId); @@ -2477,9 +2400,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public Set getLabels(final String groupId) { - final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); - group.authorize(authorizer, RequestAction.READ); - final Set