Repository: nifi Updated Branches: refs/heads/master c2b26eb31 -> fbd299e88
http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/LabelAccessControlTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/LabelAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/LabelAccessControlTest.java new file mode 100644 index 0000000..ebfc3c2 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/LabelAccessControlTest.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.integration.accesscontrol; + +import com.sun.jersey.api.client.ClientResponse; +import org.apache.nifi.integration.util.NiFiTestAuthorizer; +import org.apache.nifi.integration.util.NiFiTestUser; +import org.apache.nifi.web.api.dto.LabelDTO; +import org.apache.nifi.web.api.dto.RevisionDTO; +import org.apache.nifi.web.api.dto.flow.FlowDTO; +import org.apache.nifi.web.api.entity.LabelEntity; +import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.NONE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_WRITE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.WRITE_CLIENT_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Access control test for labels. + */ +public class LabelAccessControlTest { + + private static final String FLOW_XML_PATH = "target/test-classes/access-control/flow-labels.xml"; + + private static AccessControlHelper helper; + + @BeforeClass + public static void setup() throws Exception { + helper = new AccessControlHelper(FLOW_XML_PATH); + } + + /** + * Ensures the READ user can get a label. + * + * @throws Exception ex + */ + @Test + public void testReadUserGetLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the READ WRITE user can get a label. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserGetLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the WRITE user can get a label. + * + * @throws Exception ex + */ + @Test + public void testWriteUserGetLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the NONE user can get a label. + * + * @throws Exception ex + */ + @Test + public void testNoneUserGetLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the READ user cannot put a label. + * + * @throws Exception ex + */ + @Test + public void testReadUserPutLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + // attempt update the name + entity.getRevision().setClientId(READ_CLIENT_ID); + entity.getComponent().setLabel("Updated Label"); + + // perform the request + final ClientResponse response = updateLabel(helper.getReadUser(), entity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ_WRITE user can put a label. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String updatedLabel = "Updated Name"; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(AccessControlHelper.READ_WRITE_CLIENT_ID); + entity.getComponent().setLabel(updatedLabel); + + // perform the request + final ClientResponse response = updateLabel(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final LabelEntity responseEntity = response.getEntity(LabelEntity.class); + + // verify + assertEquals(READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedLabel, responseEntity.getComponent().getLabel()); + } + + /** + * Ensures the READ_WRITE user can put a label. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutLabelThroughInheritedPolicy() throws Exception { + final LabelEntity entity = createLabel(NiFiTestAuthorizer.NO_POLICY_COMPONENT_NAME); + + final String updatedLabel = "Updated name"; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(READ_WRITE_CLIENT_ID); + entity.getComponent().setLabel(updatedLabel); + + // perform the request + final ClientResponse response = updateLabel(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final LabelEntity responseEntity = response.getEntity(LabelEntity.class); + + // verify + assertEquals(AccessControlHelper.READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedLabel, responseEntity.getComponent().getLabel()); + } + + /** + * Ensures the WRITE user can put a label. + * + * @throws Exception ex + */ + @Test + public void testWriteUserPutLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedLabel = "Updated Name"; + + // attempt to update the label + final LabelDTO requestDto = new LabelDTO(); + requestDto.setId(entity.getId()); + requestDto.setLabel(updatedLabel); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.WRITE_CLIENT_ID); + + final LabelEntity requestEntity = new LabelEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateLabel(helper.getWriteUser(), requestEntity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final LabelEntity responseEntity = response.getEntity(LabelEntity.class); + + // verify + assertEquals(WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + } + + /** + * Ensures the NONE user cannot put a label. + * + * @throws Exception ex + */ + @Test + public void testNoneUserPutLabel() throws Exception { + final LabelEntity entity = getRandomLabel(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name"; + + // attempt to update the name + final LabelDTO requestDto = new LabelDTO(); + requestDto.setId(entity.getId()); + requestDto.setLabel(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.NONE_CLIENT_ID); + + final LabelEntity requestEntity = new LabelEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateLabel(helper.getNoneUser(), requestEntity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ user cannot delete a label. + * + * @throws Exception ex + */ + @Test + public void testReadUserDeleteLabel() throws Exception { + verifyDelete(helper.getReadUser(), AccessControlHelper.READ_CLIENT_ID, 403); + } + + /** + * Ensures the READ WRITE user can delete a label. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserDeleteLabel() throws Exception { + verifyDelete(helper.getReadWriteUser(), AccessControlHelper.READ_WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the WRITE user can delete a label. + * + * @throws Exception ex + */ + @Test + public void testWriteUserDeleteLabel() throws Exception { + verifyDelete(helper.getWriteUser(), AccessControlHelper.WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the NONE user can delete a label. + * + * @throws Exception ex + */ + @Test + public void testNoneUserDeleteLabel() throws Exception { + verifyDelete(helper.getNoneUser(), NONE_CLIENT_ID, 403); + } + + private LabelEntity getRandomLabel(final NiFiTestUser user) throws Exception { + final String url = helper.getBaseUrl() + "/flow/process-groups/root"; + + // get the labels + final ClientResponse response = user.testGet(url); + + // ensure the response was successful + assertEquals(200, response.getStatus()); + + // unmarshal + final ProcessGroupFlowEntity flowEntity = response.getEntity(ProcessGroupFlowEntity.class); + final FlowDTO flowDto = flowEntity.getProcessGroupFlow().getFlow(); + final Set<LabelEntity> labels = flowDto.getLabels(); + + // ensure the correct number of labels + assertFalse(labels.isEmpty()); + + // use the first label as the target + Iterator<LabelEntity> labelIter = labels.iterator(); + assertTrue(labelIter.hasNext()); + return labelIter.next(); + } + + private ClientResponse updateLabel(final NiFiTestUser user, final LabelEntity entity) throws Exception { + final String url = helper.getBaseUrl() + "/labels/" + entity.getId(); + + // perform the request + return user.testPut(url, entity); + } + + private LabelEntity createLabel(final String name) throws Exception { + String url = helper.getBaseUrl() + "/process-groups/root/labels"; + + // create the label + LabelDTO label = new LabelDTO(); + label.setLabel(name); + + // create the revision + final RevisionDTO revision = new RevisionDTO(); + revision.setClientId(READ_WRITE_CLIENT_ID); + revision.setVersion(0L); + + // create the entity body + LabelEntity entity = new LabelEntity(); + entity.setRevision(revision); + entity.setComponent(label); + + // perform the request + ClientResponse response = helper.getReadWriteUser().testPost(url, entity); + + // ensure the request is successful + assertEquals(201, response.getStatus()); + + // get the entity body + entity = response.getEntity(LabelEntity.class); + + // verify creation + label = entity.getComponent(); + assertEquals(name, label.getLabel()); + + // get the label id + return entity; + } + + private void verifyDelete(final NiFiTestUser user, final String clientId, final int responseCode) throws Exception { + final LabelEntity entity = createLabel("Copy"); + + // create the entity body + final Map<String, String> queryParams = new HashMap<>(); + queryParams.put("revision", String.valueOf(entity.getRevision().getVersion())); + queryParams.put("clientId", clientId); + + // perform the request + ClientResponse response = user.testDelete(entity.getComponent().getUri(), queryParams); + + // ensure the request is failed with a forbidden status code + assertEquals(responseCode, response.getStatus()); + } + + @AfterClass + public static void cleanup() throws Exception { + helper.cleanup(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OutputPortAccessControlTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OutputPortAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OutputPortAccessControlTest.java new file mode 100644 index 0000000..900b11f --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/OutputPortAccessControlTest.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.integration.accesscontrol; + +import com.sun.jersey.api.client.ClientResponse; +import org.apache.nifi.integration.util.NiFiTestAuthorizer; +import org.apache.nifi.integration.util.NiFiTestUser; +import org.apache.nifi.web.api.dto.PortDTO; +import org.apache.nifi.web.api.dto.RevisionDTO; +import org.apache.nifi.web.api.dto.flow.FlowDTO; +import org.apache.nifi.web.api.entity.PortEntity; +import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.NONE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_WRITE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.WRITE_CLIENT_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Access control test for output ports. + */ +public class OutputPortAccessControlTest { + + private static final String FLOW_XML_PATH = "target/test-classes/access-control/flow-output-ports.xml"; + + private static AccessControlHelper helper; + private static int count = 0; + + @BeforeClass + public static void setup() throws Exception { + helper = new AccessControlHelper(FLOW_XML_PATH); + } + + /** + * Ensures the READ user can get an output port. + * + * @throws Exception ex + */ + @Test + public void testReadUserGetOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the READ WRITE user can get an output port. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserGetOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the WRITE user can get an output port. + * + * @throws Exception ex + */ + @Test + public void testWriteUserGetOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the NONE user can get an output port. + * + * @throws Exception ex + */ + @Test + public void testNoneUserGetOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the READ user cannot put an output port. + * + * @throws Exception ex + */ + @Test + public void testReadUserPutOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + // attempt update the name + entity.getRevision().setClientId(READ_CLIENT_ID); + entity.getComponent().setName("Updated Name" + count++); + + // perform the request + final ClientResponse response = updateOutputPort(helper.getReadUser(), entity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ_WRITE user can put an output port. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(AccessControlHelper.READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateOutputPort(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final PortEntity responseEntity = response.getEntity(PortEntity.class); + + // verify + assertEquals(READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the READ_WRITE user can put an output port. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutOutputPortThroughInheritedPolicy() throws Exception { + final PortEntity entity = createOutputPort(NiFiTestAuthorizer.NO_POLICY_COMPONENT_NAME); + + final String updatedName = "Updated name" + count++; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateOutputPort(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final PortEntity responseEntity = response.getEntity(PortEntity.class); + + // verify + assertEquals(AccessControlHelper.READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the WRITE user can put an output port. + * + * @throws Exception ex + */ + @Test + public void testWriteUserPutOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final PortDTO requestDto = new PortDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.WRITE_CLIENT_ID); + + final PortEntity requestEntity = new PortEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateOutputPort(helper.getWriteUser(), requestEntity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final PortEntity responseEntity = response.getEntity(PortEntity.class); + + // verify + assertEquals(WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + } + + /** + * Ensures the NONE user cannot put an output port. + * + * @throws Exception ex + */ + @Test + public void testNoneUserPutOutputPort() throws Exception { + final PortEntity entity = getRandomOutputPort(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final PortDTO requestDto = new PortDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.NONE_CLIENT_ID); + + final PortEntity requestEntity = new PortEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateOutputPort(helper.getNoneUser(), requestEntity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ user cannot delete an output port. + * + * @throws Exception ex + */ + @Test + public void testReadUserDeleteOutputPort() throws Exception { + verifyDelete(helper.getReadUser(), AccessControlHelper.READ_CLIENT_ID, 403); + } + + /** + * Ensures the READ WRITE user can delete an output port. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserDeleteOutputPort() throws Exception { + verifyDelete(helper.getReadWriteUser(), AccessControlHelper.READ_WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the WRITE user can delete an Output port. + * + * @throws Exception ex + */ + @Test + public void testWriteUserDeleteOutputPort() throws Exception { + verifyDelete(helper.getWriteUser(), AccessControlHelper.WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the NONE user can delete an Output port. + * + * @throws Exception ex + */ + @Test + public void testNoneUserDeleteOutputPort() throws Exception { + verifyDelete(helper.getNoneUser(), NONE_CLIENT_ID, 403); + } + + private PortEntity getRandomOutputPort(final NiFiTestUser user) throws Exception { + final String url = helper.getBaseUrl() + "/flow/process-groups/root"; + + // get the output ports + final ClientResponse response = user.testGet(url); + + // ensure the response was successful + assertEquals(200, response.getStatus()); + + // unmarshal + final ProcessGroupFlowEntity flowEntity = response.getEntity(ProcessGroupFlowEntity.class); + final FlowDTO flowDto = flowEntity.getProcessGroupFlow().getFlow(); + final Set<PortEntity> outputPorts = flowDto.getOutputPorts(); + + // ensure the correct number of output ports + assertFalse(outputPorts.isEmpty()); + + // use the first output port as the target + Iterator<PortEntity> outputPortIter = outputPorts.iterator(); + assertTrue(outputPortIter.hasNext()); + return outputPortIter.next(); + } + + private ClientResponse updateOutputPort(final NiFiTestUser user, final PortEntity entity) throws Exception { + final String url = helper.getBaseUrl() + "/output-ports/" + entity.getId(); + + // perform the request + return user.testPut(url, entity); + } + + private PortEntity createOutputPort(final String name) throws Exception { + String url = helper.getBaseUrl() + "/process-groups/root/output-ports"; + + final String updatedName = name + count++; + + // create the output port + PortDTO outputPort = new PortDTO(); + outputPort.setName(updatedName); + + // create the revision + final RevisionDTO revision = new RevisionDTO(); + revision.setClientId(READ_WRITE_CLIENT_ID); + revision.setVersion(0L); + + // create the entity body + PortEntity entity = new PortEntity(); + entity.setRevision(revision); + entity.setComponent(outputPort); + + // perform the request + ClientResponse response = helper.getReadWriteUser().testPost(url, entity); + + // ensure the request is successful + assertEquals(201, response.getStatus()); + + // get the entity body + entity = response.getEntity(PortEntity.class); + + // verify creation + outputPort = entity.getComponent(); + assertEquals(updatedName, outputPort.getName()); + + // get the output port + return entity; + } + + private void verifyDelete(final NiFiTestUser user, final String clientId, final int responseCode) throws Exception { + final PortEntity entity = createOutputPort("Copy"); + + // create the entity body + final Map<String, String> queryParams = new HashMap<>(); + queryParams.put("revision", String.valueOf(entity.getRevision().getVersion())); + queryParams.put("clientId", clientId); + + // perform the request + ClientResponse response = user.testDelete(entity.getComponent().getUri(), queryParams); + + // ensure the request is failed with a forbidden status code + assertEquals(responseCode, response.getStatus()); + } + + @AfterClass + public static void cleanup() throws Exception { + helper.cleanup(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessGroupAccessControlTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessGroupAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessGroupAccessControlTest.java new file mode 100644 index 0000000..b3179b1 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessGroupAccessControlTest.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.integration.accesscontrol; + +import com.sun.jersey.api.client.ClientResponse; +import org.apache.nifi.integration.util.NiFiTestAuthorizer; +import org.apache.nifi.integration.util.NiFiTestUser; +import org.apache.nifi.web.api.dto.ProcessGroupDTO; +import org.apache.nifi.web.api.dto.RevisionDTO; +import org.apache.nifi.web.api.dto.flow.FlowDTO; +import org.apache.nifi.web.api.entity.ProcessGroupEntity; +import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.NONE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_WRITE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.WRITE_CLIENT_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Access control test for process groups. + */ +public class ProcessGroupAccessControlTest { + + private static final String FLOW_XML_PATH = "target/test-classes/access-control/flow-processors.xml"; + + private static AccessControlHelper helper; + private static int count = 0; + + @BeforeClass + public static void setup() throws Exception { + helper = new AccessControlHelper(FLOW_XML_PATH); + } + + /** + * Ensures the READ user can get a process group. + * + * @throws Exception ex + */ + @Test + public void testReadUserGetProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the READ WRITE user can get a process group. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserGetProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the WRITE user can get a process group. + * + * @throws Exception ex + */ + @Test + public void testWriteUserGetProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the NONE user can get a process group. + * + * @throws Exception ex + */ + @Test + public void testNoneUserGetProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the READ user cannot put a processor. + * + * @throws Exception ex + */ + @Test + public void testReadUserPutProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + // attempt update the name + entity.getRevision().setClientId(READ_CLIENT_ID); + entity.getComponent().setName("Updated Name" + count++); + + // perform the request + final ClientResponse response = updateProcessGroup(helper.getReadUser(), entity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ_WRITE user can put a process group. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(AccessControlHelper.READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateProcessGroup(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessGroupEntity responseEntity = response.getEntity(ProcessGroupEntity.class); + + // verify + assertEquals(READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the READ_WRITE user can put a process grup. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutProcessGroupThroughInheritedPolicy() throws Exception { + final ProcessGroupEntity entity = createProcessGroup(NiFiTestAuthorizer.NO_POLICY_COMPONENT_NAME); + + final String updatedName = "Updated name" + count++; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateProcessGroup(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessGroupEntity responseEntity = response.getEntity(ProcessGroupEntity.class); + + // verify + assertEquals(AccessControlHelper.READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the WRITE user can put a process group. + * + * @throws Exception ex + */ + @Test + public void testWriteUserPutProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final ProcessGroupDTO requestDto = new ProcessGroupDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.WRITE_CLIENT_ID); + + final ProcessGroupEntity requestEntity = new ProcessGroupEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateProcessGroup(helper.getWriteUser(), requestEntity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessGroupEntity responseEntity = response.getEntity(ProcessGroupEntity.class); + + // verify + assertEquals(WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + } + + /** + * Ensures the NONE user cannot put a process group. + * + * @throws Exception ex + */ + @Test + public void testNoneUserPutProcessGroup() throws Exception { + final ProcessGroupEntity entity = getRandomProcessGroup(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name" + count++; + + // attempt to update the name + final ProcessGroupDTO requestDto = new ProcessGroupDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.NONE_CLIENT_ID); + + final ProcessGroupEntity requestEntity = new ProcessGroupEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateProcessGroup(helper.getNoneUser(), requestEntity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ user cannot delete a process group. + * + * @throws Exception ex + */ + @Test + public void testReadUserDeleteProcessGroup() throws Exception { + verifyDelete(helper.getReadUser(), AccessControlHelper.READ_CLIENT_ID, 403); + } + + /** + * Ensures the READ WRITE user can delete a process group. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserDeleteProcessGroup() throws Exception { + verifyDelete(helper.getReadWriteUser(), AccessControlHelper.READ_WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the WRITE user can delete a process group. + * + * @throws Exception ex + */ + @Test + public void testWriteUserDeleteProcessGroup() throws Exception { + verifyDelete(helper.getWriteUser(), AccessControlHelper.WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the NONE user can delete a process group. + * + * @throws Exception ex + */ + @Test + public void testNoneUserDeleteProcessGroup() throws Exception { + verifyDelete(helper.getNoneUser(), NONE_CLIENT_ID, 403); + } + + private ProcessGroupEntity getRandomProcessGroup(final NiFiTestUser user) throws Exception { + final String url = helper.getBaseUrl() + "/flow/process-groups/root"; + + // get the process groups + final ClientResponse response = user.testGet(url); + + // ensure the response was successful + assertEquals(200, response.getStatus()); + + // unmarshal + final ProcessGroupFlowEntity flowEntity = response.getEntity(ProcessGroupFlowEntity.class); + final FlowDTO flowDto = flowEntity.getProcessGroupFlow().getFlow(); + final Set<ProcessGroupEntity> processGroups = flowDto.getProcessGroups(); + + // ensure the correct number of process groups + assertFalse(processGroups.isEmpty()); + + // use the first process group as the target + Iterator<ProcessGroupEntity> processGroupIter = processGroups.iterator(); + assertTrue(processGroupIter.hasNext()); + return processGroupIter.next(); + } + + private ClientResponse updateProcessGroup(final NiFiTestUser user, final ProcessGroupEntity entity) throws Exception { + final String url = helper.getBaseUrl() + "/process-groups/" + entity.getId(); + + // perform the request + return user.testPut(url, entity); + } + + private ProcessGroupEntity createProcessGroup(final String name) throws Exception { + String url = helper.getBaseUrl() + "/process-groups/root/process-groups"; + + final String updatedName = name + count++; + + // create the process group + ProcessGroupDTO processor = new ProcessGroupDTO(); + processor.setName(updatedName); + + // create the revision + final RevisionDTO revision = new RevisionDTO(); + revision.setClientId(READ_WRITE_CLIENT_ID); + revision.setVersion(0L); + + // create the entity body + ProcessGroupEntity entity = new ProcessGroupEntity(); + entity.setRevision(revision); + entity.setComponent(processor); + + // perform the request + ClientResponse response = helper.getReadWriteUser().testPost(url, entity); + + // ensure the request is successful + assertEquals(201, response.getStatus()); + + // get the entity body + entity = response.getEntity(ProcessGroupEntity.class); + + // verify creation + processor = entity.getComponent(); + assertEquals(updatedName, processor.getName()); + + // get the processor + return entity; + } + + private void verifyDelete(final NiFiTestUser user, final String clientId, final int responseCode) throws Exception { + final ProcessGroupEntity entity = createProcessGroup("Copy"); + + // create the entity body + final Map<String, String> queryParams = new HashMap<>(); + queryParams.put("revision", String.valueOf(entity.getRevision().getVersion())); + queryParams.put("clientId", clientId); + + // perform the request + ClientResponse response = user.testDelete(entity.getComponent().getUri(), queryParams); + + // ensure the request is failed with a forbidden status code + assertEquals(responseCode, response.getStatus()); + } + + @AfterClass + public static void cleanup() throws Exception { + helper.cleanup(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessorAccessControlTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessorAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessorAccessControlTest.java new file mode 100644 index 0000000..80b6b76 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ProcessorAccessControlTest.java @@ -0,0 +1,489 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.integration.accesscontrol; + +import com.sun.jersey.api.client.ClientResponse; +import org.apache.nifi.integration.util.NiFiTestAuthorizer; +import org.apache.nifi.integration.util.NiFiTestUser; +import org.apache.nifi.integration.util.SourceTestProcessor; +import org.apache.nifi.web.api.dto.ProcessorDTO; +import org.apache.nifi.web.api.dto.RevisionDTO; +import org.apache.nifi.web.api.dto.flow.FlowDTO; +import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity; +import org.apache.nifi.web.api.entity.ProcessorEntity; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.NONE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.READ_WRITE_CLIENT_ID; +import static org.apache.nifi.integration.accesscontrol.AccessControlHelper.WRITE_CLIENT_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Access control test for processors. + */ +public class ProcessorAccessControlTest { + + private static final String FLOW_XML_PATH = "target/test-classes/access-control/flow-processors.xml"; + + private static AccessControlHelper helper; + + @BeforeClass + public static void setup() throws Exception { + helper = new AccessControlHelper(FLOW_XML_PATH); + } + + /** + * Ensures the READ user can get a processor. + * + * @throws Exception ex + */ + @Test + public void testReadUserGetProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the READ WRITE user can get a processor. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserGetProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + } + + /** + * Ensures the WRITE user can get a processor. + * + * @throws Exception ex + */ + @Test + public void testWriteUserGetProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the NONE user can get a processor. + * + * @throws Exception ex + */ + @Test + public void testNoneUserGetProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + } + + /** + * Ensures the READ user cannot put a processor. + * + * @throws Exception ex + */ + @Test + public void testReadUserPutProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + // attempt update the name + entity.getRevision().setClientId(READ_CLIENT_ID); + entity.getComponent().setName("Updated Name"); + + // perform the request + final ClientResponse response = updateProcessor(helper.getReadUser(), entity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ_WRITE user can put a processor. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadWriteUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String updatedName = "Updated Name"; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(AccessControlHelper.READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateProcessor(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessorEntity responseEntity = response.getEntity(ProcessorEntity.class); + + // verify + assertEquals(READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the READ_WRITE user can put a processor. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserPutProcessorThroughInheritedPolicy() throws Exception { + final ProcessorEntity entity = createProcessor(helper, NiFiTestAuthorizer.NO_POLICY_COMPONENT_NAME); + + final String updatedName = "Updated name"; + + // attempt to update the name + final long version = entity.getRevision().getVersion(); + entity.getRevision().setClientId(READ_WRITE_CLIENT_ID); + entity.getComponent().setName(updatedName); + + // perform the request + final ClientResponse response = updateProcessor(helper.getReadWriteUser(), entity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessorEntity responseEntity = response.getEntity(ProcessorEntity.class); + + // verify + assertEquals(AccessControlHelper.READ_WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + assertEquals(updatedName, responseEntity.getComponent().getName()); + } + + /** + * Ensures the WRITE user can put a processor. + * + * @throws Exception ex + */ + @Test + public void testWriteUserPutProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getWriteUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertTrue(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name"; + + // attempt to update the name + final ProcessorDTO requestDto = new ProcessorDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.WRITE_CLIENT_ID); + + final ProcessorEntity requestEntity = new ProcessorEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateProcessor(helper.getWriteUser(), requestEntity); + + // ensure successful response + assertEquals(200, response.getStatus()); + + // get the response + final ProcessorEntity responseEntity = response.getEntity(ProcessorEntity.class); + + // verify + assertEquals(WRITE_CLIENT_ID, responseEntity.getRevision().getClientId()); + assertEquals(version + 1, responseEntity.getRevision().getVersion().longValue()); + } + + /** + * Ensures the NONE user cannot put a processor. + * + * @throws Exception ex + */ + @Test + public void testNoneUserPutProcessor() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getNoneUser()); + assertFalse(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNull(entity.getComponent()); + + final String updatedName = "Updated Name"; + + // attempt to update the name + final ProcessorDTO requestDto = new ProcessorDTO(); + requestDto.setId(entity.getId()); + requestDto.setName(updatedName); + + final long version = entity.getRevision().getVersion(); + final RevisionDTO requestRevision = new RevisionDTO(); + requestRevision.setVersion(version); + requestRevision.setClientId(AccessControlHelper.NONE_CLIENT_ID); + + final ProcessorEntity requestEntity = new ProcessorEntity(); + requestEntity.setId(entity.getId()); + requestEntity.setRevision(requestRevision); + requestEntity.setComponent(requestDto); + + // perform the request + final ClientResponse response = updateProcessor(helper.getNoneUser(), requestEntity); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ user cannot clear state. + * + * @throws Exception ex + */ + @Test + public void testReadUserClearState() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String url = helper.getBaseUrl() + "/processors/" + entity.getId() + "/state/clear-requests"; + + // perform the request + final ClientResponse response = helper.getReadUser().testPost(url); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the NONE user cannot clear state. + * + * @throws Exception ex + */ + @Test + public void testNoneUserClearState() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String url = helper.getBaseUrl() + "/processors/" + entity.getId() + "/state/clear-requests"; + + // perform the request + final ClientResponse response = helper.getNoneUser().testPost(url); + + // ensure forbidden response + assertEquals(403, response.getStatus()); + } + + /** + * Ensures the READ WRITE user can clear state. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserClearState() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String url = helper.getBaseUrl() + "/processors/" + entity.getId() + "/state/clear-requests"; + + // perform the request + final ClientResponse response = helper.getReadWriteUser().testPost(url); + + // ensure ok response + assertEquals(200, response.getStatus()); + } + + /** + * Ensures the WRITE user can clear state. + * + * @throws Exception ex + */ + @Test + public void testWriteUserClearState() throws Exception { + final ProcessorEntity entity = getRandomProcessor(helper.getReadUser()); + assertTrue(entity.getAccessPolicy().getCanRead()); + assertFalse(entity.getAccessPolicy().getCanWrite()); + assertNotNull(entity.getComponent()); + + final String url = helper.getBaseUrl() + "/processors/" + entity.getId() + "/state/clear-requests"; + + // perform the request + final ClientResponse response = helper.getWriteUser().testPost(url); + + // ensure ok response + assertEquals(200, response.getStatus()); + } + + /** + * Ensures the READ user cannot delete a processor. + * + * @throws Exception ex + */ + @Test + public void testReadUserDeleteProcessor() throws Exception { + verifyDelete(helper.getReadUser(), AccessControlHelper.READ_CLIENT_ID, 403); + } + + /** + * Ensures the READ WRITE user can delete a processor. + * + * @throws Exception ex + */ + @Test + public void testReadWriteUserDeleteProcessor() throws Exception { + verifyDelete(helper.getReadWriteUser(), AccessControlHelper.READ_WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the WRITE user can delete a processor. + * + * @throws Exception ex + */ + @Test + public void testWriteUserDeleteProcessor() throws Exception { + verifyDelete(helper.getWriteUser(), AccessControlHelper.WRITE_CLIENT_ID, 200); + } + + /** + * Ensures the NONE user can delete a processor. + * + * @throws Exception ex + */ + @Test + public void testNoneUserDeleteProcessor() throws Exception { + verifyDelete(helper.getNoneUser(), NONE_CLIENT_ID, 403); + } + + private ProcessorEntity getRandomProcessor(final NiFiTestUser user) throws Exception { + final String url = helper.getBaseUrl() + "/flow/process-groups/root"; + + // get the processors + final ClientResponse response = user.testGet(url); + + // ensure the response was successful + assertEquals(200, response.getStatus()); + + // unmarshal + final ProcessGroupFlowEntity flowEntity = response.getEntity(ProcessGroupFlowEntity.class); + final FlowDTO flowDto = flowEntity.getProcessGroupFlow().getFlow(); + final Set<ProcessorEntity> processors = flowDto.getProcessors(); + + // ensure the correct number of processors + assertFalse(processors.isEmpty()); + + // use the first processor as the target + Iterator<ProcessorEntity> processorIter = processors.iterator(); + assertTrue(processorIter.hasNext()); + return processorIter.next(); + } + + private ClientResponse updateProcessor(final NiFiTestUser user, final ProcessorEntity entity) throws Exception { + final String url = helper.getBaseUrl() + "/processors/" + entity.getId(); + + // perform the request + return user.testPut(url, entity); + } + + public static ProcessorEntity createProcessor(final AccessControlHelper ach, final String name) throws Exception { + String url = ach.getBaseUrl() + "/process-groups/root/processors"; + + // create the processor + ProcessorDTO processor = new ProcessorDTO(); + processor.setName(name); + processor.setType(SourceTestProcessor.class.getName()); + + // create the revision + final RevisionDTO revision = new RevisionDTO(); + revision.setClientId(READ_WRITE_CLIENT_ID); + revision.setVersion(0L); + + // create the entity body + ProcessorEntity entity = new ProcessorEntity(); + entity.setRevision(revision); + entity.setComponent(processor); + + // perform the request + ClientResponse response = ach.getReadWriteUser().testPost(url, entity); + + // ensure the request is successful + assertEquals(201, response.getStatus()); + + // get the entity body + entity = response.getEntity(ProcessorEntity.class); + + // verify creation + processor = entity.getComponent(); + assertEquals(name, processor.getName()); + assertEquals("org.apache.nifi.integration.util.SourceTestProcessor", processor.getType()); + + // get the processor + return entity; + } + + private void verifyDelete(final NiFiTestUser user, final String clientId, final int responseCode) throws Exception { + final ProcessorEntity entity = createProcessor(helper, "Copy"); + + // create the entity body + final Map<String, String> queryParams = new HashMap<>(); + queryParams.put("revision", String.valueOf(entity.getRevision().getVersion())); + queryParams.put("clientId", clientId); + + // perform the request + ClientResponse response = user.testDelete(entity.getComponent().getUri(), queryParams); + + // ensure the request is failed with a forbidden status code + assertEquals(responseCode, response.getStatus()); + } + + @AfterClass + public static void cleanup() throws Exception { + helper.cleanup(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java index 5795b69..419235f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestAuthorizer.java @@ -21,14 +21,26 @@ import org.apache.nifi.authorization.AuthorizationResult; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.AuthorizerConfigurationContext; import org.apache.nifi.authorization.AuthorizerInitializationContext; +import org.apache.nifi.authorization.RequestAction; import org.apache.nifi.authorization.exception.AuthorizationAccessException; import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.resource.ResourceFactory; /** * */ public class NiFiTestAuthorizer implements Authorizer { + public static final String NO_POLICY_COMPONENT_NAME = "No policies"; + + public static final String PROXY_DN = "CN=localhost, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US"; + + public static final String NONE_USER_DN = "none@nifi"; + public static final String READ_USER_DN = "read@nifi"; + public static final String WRITE_USER_DN = "write@nifi"; + public static final String READ_WRITE_USER_DN = "readwrite@nifi"; + + public static final String TOKEN_USER = "user@nifi"; /** * Creates a new FileAuthorizationProvider. @@ -46,7 +58,41 @@ public class NiFiTestAuthorizer implements Authorizer { @Override public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException { - return AuthorizationResult.approved(); + // allow proxy + if (ResourceFactory.getProxyResource().getIdentifier().equals(request.getResource().getIdentifier()) && PROXY_DN.equals(request.getIdentity())) { + return AuthorizationResult.approved(); + } + + // allow flow + if (ResourceFactory.getFlowResource().getIdentifier().equals(request.getResource().getIdentifier())) { + return AuthorizationResult.approved(); + } + + // no policy to test inheritance + if (NO_POLICY_COMPONENT_NAME.equals(request.getResource().getName())) { + return AuthorizationResult.resourceNotFound(); + } + + // allow the token user + if (TOKEN_USER.equals(request.getIdentity())) { + return AuthorizationResult.approved(); + } + + // read access + if (READ_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity())) { + if (RequestAction.READ.equals(request.getAction())) { + return AuthorizationResult.approved(); + } + } + + // write access + if (WRITE_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity())) { + if (RequestAction.WRITE.equals(request.getAction())) { + return AuthorizationResult.approved(); + } + } + + return AuthorizationResult.denied(); } @Override http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/SourceTestProcessor.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/SourceTestProcessor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/SourceTestProcessor.java index 0309ebb..2fe6b46 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/SourceTestProcessor.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/SourceTestProcessor.java @@ -16,9 +16,8 @@ */ package org.apache.nifi.integration.util; -import java.util.HashSet; -import java.util.Set; - +import org.apache.nifi.annotation.behavior.Stateful; +import org.apache.nifi.components.state.Scope; import org.apache.nifi.processor.AbstractSessionFactoryProcessor; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSessionFactory; @@ -26,6 +25,10 @@ import org.apache.nifi.processor.ProcessorInitializationContext; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; +import java.util.HashSet; +import java.util.Set; + +@Stateful(scopes = Scope.LOCAL, description = "") public class SourceTestProcessor extends AbstractSessionFactoryProcessor { public SourceTestProcessor() { http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authority-providers.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authority-providers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authority-providers.xml deleted file mode 100644 index a3fb088..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authority-providers.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<!-- - 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. ---> -<!-- - This file lists all authority providers to use when running securely. ---> -<authorityProviders> - <provider> - <identifier>test-provider</identifier> - <class>org.apache.nifi.integration.util.NiFiTestAuthorizer</class> - </provider> -</authorityProviders> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authorizers.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authorizers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authorizers.xml new file mode 100644 index 0000000..18161d6 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/authorizers.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + 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. +--> +<!-- + This file lists all authority providers to use when running securely. +--> +<authorizers> + <authorizer> + <identifier>test-provider</identifier> + <class>org.apache.nifi.integration.util.NiFiTestAuthorizer</class> + </authorizer> +</authorizers> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties index a41e3b1..4df1e3d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/access-control/nifi.properties @@ -21,7 +21,7 @@ nifi.flowcontroller.autoResumeState=true nifi.flowcontroller.graceful.shutdown.period=10 sec nifi.flowservice.writedelay.interval=2 sec -nifi.authority.provider.configuration.file=target/test-classes/access-control/authority-providers.xml +nifi.authorizer.configuration.file=target/test-classes/access-control/authorizers.xml nifi.login.identity.provider.configuration.file=target/test-classes/access-control/login-identity-providers.xml nifi.templates.directory=target/test-classes/access-control/templates nifi.ui.banner.text=TEST BANNER @@ -82,7 +82,7 @@ nifi.web.war.directory=target/test-classes/lib nifi.web.http.host= nifi.web.http.port= nifi.web.https.host= -nifi.web.https.port= +nifi.web.https.port=8443 nifi.web.jetty.working.directory=target/test-classes/access-control/jetty # security properties # @@ -99,7 +99,7 @@ nifi.security.truststoreType=JKS nifi.security.truststorePasswd=localtest nifi.security.needClientAuth=true nifi.security.user.login.identity.provider=test-provider -nifi.security.user.authorizer= +nifi.security.user.authorizer=test-provider # cluster common properties (cluster manager and nodes must have same values) # nifi.cluster.protocol.heartbeat.interval=5 sec http://git-wip-us.apache.org/repos/asf/nifi/blob/fbd299e8/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java index 2ee187a..26fae82 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java @@ -119,7 +119,7 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable } private LoginIdentityProviders loadLoginIdentityProvidersConfiguration() throws Exception { - final File loginIdentityProvidersConfigurationFile = properties.getLoginIdentityProviderConfiguraitonFile(); + final File loginIdentityProvidersConfigurationFile = properties.getLoginIdentityProviderConfigurationFile(); // load the users from the specified file if (loginIdentityProvidersConfigurationFile.exists()) {
