mirror of https://github.com/apache/nifi.git
NIFI-3135: - Authorizing restricted components on snippet usage.
- Updating REST API docs accordingly. - Adding some integration tests to exercise the additional restricted component checks. This closes #1287. Signed-off-by: Bryan Bende <bbende@apache.org>
This commit is contained in:
parent
69b23adf1b
commit
d8d29811f5
|
@ -17,7 +17,6 @@
|
|||
package org.apache.nifi.authorization;
|
||||
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
|
||||
public interface AuthorizableLookup {
|
||||
|
||||
|
@ -201,7 +200,7 @@ public interface AuthorizableLookup {
|
|||
* @param id template id
|
||||
* @return authorizable
|
||||
*/
|
||||
Authorizable getTemplate(String id);
|
||||
TemplateAuthorizable getTemplate(String id);
|
||||
|
||||
/**
|
||||
* Get the authorizable connectable.
|
||||
|
@ -217,7 +216,7 @@ public interface AuthorizableLookup {
|
|||
* @param id snippet id
|
||||
* @return snippet of authorizable's
|
||||
*/
|
||||
Snippet getSnippet(String id);
|
||||
SnippetAuthorizable getSnippet(String id);
|
||||
|
||||
/**
|
||||
* Get the {@link Authorizable} that represents the resource of users and user groups.
|
||||
|
|
|
@ -43,7 +43,7 @@ public interface ProcessGroupAuthorizable {
|
|||
*
|
||||
* @return all encapsulated connections
|
||||
*/
|
||||
Set<Authorizable> getEncapsulatedConnections();
|
||||
Set<ConnectionAuthorizable> getEncapsulatedConnections();
|
||||
|
||||
/**
|
||||
* The authorizables for all encapsulated input ports. Non null
|
||||
|
@ -78,7 +78,7 @@ public interface ProcessGroupAuthorizable {
|
|||
*
|
||||
* @return all encapsulated process groups
|
||||
*/
|
||||
Set<Authorizable> getEncapsulatedProcessGroups();
|
||||
Set<ProcessGroupAuthorizable> getEncapsulatedProcessGroups();
|
||||
|
||||
/**
|
||||
* The authorizables for all encapsulated remote process groups. Non null
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.authorization;
|
||||
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Authorizable for a Snippet.
|
||||
*/
|
||||
public interface SnippetAuthorizable {
|
||||
/**
|
||||
* The authorizables for selected processors. Non null
|
||||
*
|
||||
* @return processors
|
||||
*/
|
||||
Set<ConfigurableComponentAuthorizable> getSelectedProcessors();
|
||||
|
||||
/**
|
||||
* The authorizables for selected connections. Non null
|
||||
*
|
||||
* @return connections
|
||||
*/
|
||||
Set<ConnectionAuthorizable> getSelectedConnections();
|
||||
|
||||
/**
|
||||
* The authorizables for selected input ports. Non null
|
||||
*
|
||||
* @return input ports
|
||||
*/
|
||||
Set<Authorizable> getSelectedInputPorts();
|
||||
|
||||
/**
|
||||
* The authorizables for selected output ports. Non null
|
||||
*
|
||||
* @return output ports
|
||||
*/
|
||||
Set<Authorizable> getSelectedOutputPorts();
|
||||
|
||||
/**
|
||||
* The authorizables for selected funnels. Non null
|
||||
*
|
||||
* @return funnels
|
||||
*/
|
||||
Set<Authorizable> getSelectedFunnels();
|
||||
|
||||
/**
|
||||
* The authorizables for selected labels. Non null
|
||||
*
|
||||
* @return labels
|
||||
*/
|
||||
Set<Authorizable> getSelectedLabels();
|
||||
|
||||
/**
|
||||
* The authorizables for selected process groups. Non null
|
||||
*
|
||||
* @return process groups
|
||||
*/
|
||||
Set<ProcessGroupAuthorizable> getSelectedProcessGroups();
|
||||
|
||||
/**
|
||||
* The authorizables for selected remote process groups. Non null
|
||||
*
|
||||
* @return remote process groups
|
||||
*/
|
||||
Set<Authorizable> getSelectedRemoteProcessGroups();
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.apache.nifi.controller.ConfiguredComponent;
|
|||
import org.apache.nifi.controller.ProcessorNode;
|
||||
import org.apache.nifi.controller.ReportingTaskNode;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
import org.apache.nifi.controller.Template;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceReference;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
|
@ -41,6 +42,8 @@ import org.apache.nifi.groups.RemoteProcessGroup;
|
|||
import org.apache.nifi.remote.PortAuthorizationResult;
|
||||
import org.apache.nifi.remote.RootGroupPort;
|
||||
import org.apache.nifi.web.ResourceNotFoundException;
|
||||
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||
import org.apache.nifi.web.api.dto.TemplateDTO;
|
||||
import org.apache.nifi.web.controller.ControllerFacade;
|
||||
import org.apache.nifi.web.dao.AccessPolicyDAO;
|
||||
import org.apache.nifi.web.dao.ConnectionDAO;
|
||||
|
@ -55,6 +58,7 @@ import org.apache.nifi.web.dao.ReportingTaskDAO;
|
|||
import org.apache.nifi.web.dao.SnippetDAO;
|
||||
import org.apache.nifi.web.dao.TemplateDAO;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -221,91 +225,13 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
@Override
|
||||
public ConnectionAuthorizable getConnection(final String id) {
|
||||
final Connection connection = connectionDAO.getConnection(id);
|
||||
return new ConnectionAuthorizable() {
|
||||
@Override
|
||||
public Authorizable getAuthorizable() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connectable getSource() {
|
||||
return connection.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connectable getDestination() {
|
||||
return connection.getDestination();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessGroup getParentGroup() {
|
||||
return connection.getProcessGroup();
|
||||
}
|
||||
};
|
||||
return new StandardConnectionAuthorizable(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessGroupAuthorizable getProcessGroup(final String id) {
|
||||
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(id);
|
||||
|
||||
return new ProcessGroupAuthorizable() {
|
||||
@Override
|
||||
public Authorizable getAuthorizable() {
|
||||
return processGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors() {
|
||||
return processGroup.findAllProcessors().stream().map(
|
||||
processorNode -> new ProcessorConfigurableComponentAuthorizable(processorNode)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedConnections() {
|
||||
return processGroup.findAllConnections().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedInputPorts() {
|
||||
return processGroup.findAllInputPorts().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedOutputPorts() {
|
||||
return processGroup.findAllOutputPorts().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedFunnels() {
|
||||
return processGroup.findAllFunnels().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedLabels() {
|
||||
return processGroup.findAllLabels().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedProcessGroups() {
|
||||
return processGroup.findAllProcessGroups().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedRemoteProcessGroups() {
|
||||
return processGroup.findAllRemoteProcessGroups().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedTemplates() {
|
||||
return processGroup.findAllTemplates().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices() {
|
||||
return processGroup.findAllControllerServices().stream().map(
|
||||
controllerServiceNode -> new ControllerServiceConfigurableComponentAuthorizable(controllerServiceNode)).collect(Collectors.toSet());
|
||||
}
|
||||
};
|
||||
return new StandardProcessGroupAuthorizable(processGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -411,8 +337,75 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Snippet getSnippet(final String id) {
|
||||
return snippetDAO.getSnippet(id);
|
||||
public SnippetAuthorizable getSnippet(final String id) {
|
||||
final Snippet snippet = snippetDAO.getSnippet(id);
|
||||
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(snippet.getParentGroupId());
|
||||
|
||||
return new SnippetAuthorizable() {
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getSelectedProcessors() {
|
||||
return processGroup.getProcessors().stream()
|
||||
.filter(processor -> snippet.getProcessors().containsKey(processor.getIdentifier()))
|
||||
.map(processor -> getProcessor(processor.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConnectionAuthorizable> getSelectedConnections() {
|
||||
return processGroup.getConnections().stream()
|
||||
.filter(connection -> snippet.getConnections().containsKey(connection.getIdentifier()))
|
||||
.map(connection -> getConnection(connection.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getSelectedInputPorts() {
|
||||
return processGroup.getInputPorts().stream()
|
||||
.filter(inputPort -> snippet.getInputPorts().containsKey(inputPort.getIdentifier()))
|
||||
.map(inputPort -> getInputPort(inputPort.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getSelectedOutputPorts() {
|
||||
return processGroup.getOutputPorts().stream()
|
||||
.filter(outputPort -> snippet.getOutputPorts().containsKey(outputPort.getIdentifier()))
|
||||
.map(outputPort -> getOutputPort(outputPort.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getSelectedFunnels() {
|
||||
return processGroup.getFunnels().stream()
|
||||
.filter(funnel -> snippet.getFunnels().containsKey(funnel.getIdentifier()))
|
||||
.map(funnel -> getFunnel(funnel.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getSelectedLabels() {
|
||||
return processGroup.getLabels().stream()
|
||||
.filter(label -> snippet.getLabels().containsKey(label.getIdentifier()))
|
||||
.map(label -> getLabel(label.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProcessGroupAuthorizable> getSelectedProcessGroups() {
|
||||
return processGroup.getProcessGroups().stream()
|
||||
.filter(processGroup -> snippet.getProcessGroups().containsKey(processGroup.getIdentifier()))
|
||||
.map(processGroup -> getProcessGroup(processGroup.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getSelectedRemoteProcessGroups() {
|
||||
return processGroup.getRemoteProcessGroups().stream()
|
||||
.filter(remoteProcessGroup -> snippet.getRemoteProcessGroups().containsKey(remoteProcessGroup.getIdentifier()))
|
||||
.map(remoteProcessGroup -> getRemoteProcessGroup(remoteProcessGroup.getIdentifier()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -530,7 +523,7 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
authorizable = getReportingTask(componentId).getAuthorizable();
|
||||
break;
|
||||
case Template:
|
||||
authorizable = getTemplate(componentId);
|
||||
authorizable = getTemplate(componentId).getAuthorizable();
|
||||
break;
|
||||
case Data:
|
||||
authorizable = controllerFacade.getDataAuthorizable(componentId);
|
||||
|
@ -629,9 +622,62 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
return authorizable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates temporary instances of all processors and controller services found in the specified snippet.
|
||||
*
|
||||
* @param snippet snippet
|
||||
* @param processors processors
|
||||
* @param controllerServices controller services
|
||||
*/
|
||||
private void createTemporaryProcessorsAndControllerServices(final FlowSnippetDTO snippet,
|
||||
final Set<ConfigurableComponentAuthorizable> processors,
|
||||
final Set<ConfigurableComponentAuthorizable> controllerServices) {
|
||||
|
||||
if (snippet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (snippet.getProcessors() != null) {
|
||||
processors.addAll(snippet.getProcessors().stream().map(processor -> getProcessorByType(processor.getType())).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
if (snippet.getControllerServices() != null) {
|
||||
controllerServices.addAll(snippet.getControllerServices().stream().map(controllerService -> getControllerServiceByType(controllerService.getType())).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
if (snippet.getProcessGroups() != null) {
|
||||
snippet.getProcessGroups().stream().forEach(group -> createTemporaryProcessorsAndControllerServices(group.getContents(), processors, controllerServices));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getTemplate(final String id) {
|
||||
return templateDAO.getTemplate(id);
|
||||
public TemplateAuthorizable getTemplate(final String id) {
|
||||
final Template template = templateDAO.getTemplate(id);
|
||||
final TemplateDTO contents = template.getDetails();
|
||||
|
||||
// templates are immutable so we can pre-compute all encapsulated processors and controller services
|
||||
final Set<ConfigurableComponentAuthorizable> processors = new HashSet<>();
|
||||
final Set<ConfigurableComponentAuthorizable> controllerServices = new HashSet<>();
|
||||
|
||||
// find all processors and controller services
|
||||
createTemporaryProcessorsAndControllerServices(contents.getSnippet(), processors, controllerServices);
|
||||
|
||||
return new TemplateAuthorizable() {
|
||||
@Override
|
||||
public Authorizable getAuthorizable() {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors() {
|
||||
return processors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices() {
|
||||
return controllerServices;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -645,6 +691,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getSystem() {
|
||||
return SYSTEM_AUTHORIZABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ConfigurableComponentAuthorizable for a ProcessorNode.
|
||||
*/
|
||||
|
@ -753,9 +804,99 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getSystem() {
|
||||
return SYSTEM_AUTHORIZABLE;
|
||||
private static class StandardProcessGroupAuthorizable implements ProcessGroupAuthorizable {
|
||||
private final ProcessGroup processGroup;
|
||||
|
||||
public StandardProcessGroupAuthorizable(ProcessGroup processGroup) {
|
||||
this.processGroup = processGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getAuthorizable() {
|
||||
return processGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors() {
|
||||
return processGroup.findAllProcessors().stream().map(
|
||||
processorNode -> new ProcessorConfigurableComponentAuthorizable(processorNode)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConnectionAuthorizable> getEncapsulatedConnections() {
|
||||
return processGroup.findAllConnections().stream().map(
|
||||
connection -> new StandardConnectionAuthorizable(connection)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedInputPorts() {
|
||||
return processGroup.findAllInputPorts().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedOutputPorts() {
|
||||
return processGroup.findAllOutputPorts().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedFunnels() {
|
||||
return processGroup.findAllFunnels().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedLabels() {
|
||||
return processGroup.findAllLabels().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProcessGroupAuthorizable> getEncapsulatedProcessGroups() {
|
||||
return processGroup.findAllProcessGroups().stream().map(
|
||||
group -> new StandardProcessGroupAuthorizable(group)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedRemoteProcessGroups() {
|
||||
return processGroup.findAllRemoteProcessGroups().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getEncapsulatedTemplates() {
|
||||
return processGroup.findAllTemplates().stream().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices() {
|
||||
return processGroup.findAllControllerServices().stream().map(
|
||||
controllerServiceNode -> new ControllerServiceConfigurableComponentAuthorizable(controllerServiceNode)).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
private static class StandardConnectionAuthorizable implements ConnectionAuthorizable {
|
||||
private final Connection connection;
|
||||
|
||||
public StandardConnectionAuthorizable(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getAuthorizable() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connectable getSource() {
|
||||
return connection.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connectable getDestination() {
|
||||
return connection.getDestination();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessGroup getParentGroup() {
|
||||
return connection.getProcessGroup();
|
||||
}
|
||||
}
|
||||
|
||||
public void setProcessorDAO(ProcessorDAO processorDAO) {
|
||||
|
|
|
@ -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.authorization;
|
||||
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Authorizable for a Template.
|
||||
*/
|
||||
public interface TemplateAuthorizable {
|
||||
/**
|
||||
* Returns the authorizable for this template. Non null
|
||||
*
|
||||
* @return authorizable
|
||||
*/
|
||||
Authorizable getAuthorizable();
|
||||
|
||||
/**
|
||||
* Returns temporary instances of all encapsulated processors. Non null
|
||||
*
|
||||
* @return temporary instances of all encapsulated processors
|
||||
*/
|
||||
Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors();
|
||||
|
||||
/**
|
||||
* Returns temporary instances of all encapsulated controller services. Non null
|
||||
*
|
||||
* @return temporary instances of all encapsulated controller services
|
||||
*/
|
||||
Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices();
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
|
|||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.ProcessGroupAuthorizable;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.SnippetAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
|
@ -40,7 +41,6 @@ import org.apache.nifi.cluster.manager.exception.IllegalClusterStateException;
|
|||
import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.controller.FlowController;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
import org.apache.nifi.remote.HttpRemoteSiteListener;
|
||||
import org.apache.nifi.remote.VersionNegotiator;
|
||||
import org.apache.nifi.remote.exception.BadRequestException;
|
||||
|
@ -462,12 +462,12 @@ public abstract class ApplicationResource {
|
|||
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(processorAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||
}
|
||||
});
|
||||
processGroupAuthorizable.getEncapsulatedConnections().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedConnections().stream().map(connection -> connection.getAuthorizable()).forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedInputPorts().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedOutputPorts().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedFunnels().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedLabels().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedProcessGroups().forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedProcessGroups().stream().map(group -> group.getAuthorizable()).forEach(authorize);
|
||||
processGroupAuthorizable.getEncapsulatedRemoteProcessGroups().forEach(authorize);
|
||||
|
||||
// authorize templates if necessary
|
||||
|
@ -496,18 +496,19 @@ public abstract class ApplicationResource {
|
|||
* @param lookup lookup
|
||||
* @param action action
|
||||
*/
|
||||
protected void authorizeSnippet(final Snippet snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action,
|
||||
protected void authorizeSnippet(final SnippetAuthorizable snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action,
|
||||
final boolean authorizeReferencedServices, final boolean authorizeTransitiveServices) {
|
||||
|
||||
final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
|
||||
|
||||
// authorize each component in the specified snippet
|
||||
snippet.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(processGroupAuthorizable -> {
|
||||
snippet.getSelectedProcessGroups().stream().forEach(processGroupAuthorizable -> {
|
||||
// note - we are not authorizing templates or controller services as they are not considered when using this snippet. however,
|
||||
// referenced services are considered so those are explicitly authorized when authorizing a processor
|
||||
authorizeProcessGroup(processGroupAuthorizable, authorizer, lookup, action, authorizeReferencedServices, false, false, authorizeTransitiveServices);
|
||||
});
|
||||
snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
|
||||
snippet.getProcessors().keySet().stream().map(id -> lookup.getProcessor(id)).forEach(processorAuthorizable -> {
|
||||
snippet.getSelectedRemoteProcessGroups().stream().forEach(authorize);
|
||||
snippet.getSelectedProcessors().stream().forEach(processorAuthorizable -> {
|
||||
// authorize the processor
|
||||
authorize.accept(processorAuthorizable.getAuthorizable());
|
||||
|
||||
|
@ -516,10 +517,11 @@ public abstract class ApplicationResource {
|
|||
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(processorAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||
}
|
||||
});
|
||||
snippet.getInputPorts().keySet().stream().map(id -> lookup.getInputPort(id)).forEach(authorize);
|
||||
snippet.getOutputPorts().keySet().stream().map(id -> lookup.getOutputPort(id)).forEach(authorize);
|
||||
snippet.getConnections().keySet().stream().map(id -> lookup.getConnection(id)).forEach(connAuth -> authorize.accept(connAuth.getAuthorizable()));
|
||||
snippet.getFunnels().keySet().stream().map(id -> lookup.getFunnel(id)).forEach(authorize);
|
||||
snippet.getSelectedInputPorts().stream().forEach(authorize);
|
||||
snippet.getSelectedOutputPorts().stream().forEach(authorize);
|
||||
snippet.getSelectedConnections().stream().forEach(connAuth -> authorize.accept(connAuth.getAuthorizable()));
|
||||
snippet.getSelectedFunnels().stream().forEach(authorize);
|
||||
snippet.getSelectedLabels().stream().forEach(authorize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -238,7 +238,8 @@ public class ControllerResource extends ApplicationResource {
|
|||
response = ReportingTaskEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /controller", type = ""),
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
|
||||
@Authorization(value = "Write - if the Reporting Task is restricted - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
@ -330,7 +331,8 @@ public class ControllerResource extends ApplicationResource {
|
|||
response = ControllerServiceEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /controller", type = ""),
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
|
||||
@Authorization(value = "Write - if the Controller Service is restricted - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
|
|
@ -31,10 +31,11 @@ import org.apache.nifi.authorization.Authorizer;
|
|||
import org.apache.nifi.authorization.ConfigurableComponentAuthorizable;
|
||||
import org.apache.nifi.authorization.ProcessGroupAuthorizable;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.SnippetAuthorizable;
|
||||
import org.apache.nifi.authorization.TemplateAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
import org.apache.nifi.web.NiFiServiceFacade;
|
||||
import org.apache.nifi.web.ResourceNotFoundException;
|
||||
import org.apache.nifi.web.Revision;
|
||||
|
@ -100,6 +101,8 @@ import java.net.URISyntaxException;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* RESTful endpoint for managing a Group.
|
||||
|
@ -555,7 +558,8 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
response = ProcessorEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
|
||||
@Authorization(value = "Write - if the Processor is restricted - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
@ -1646,7 +1650,8 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
response = FlowSnippetEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||
@Authorization(value = "Read - /{component-type}/{uuid} - For each component in the snippet and their descendant components", type = "")
|
||||
@Authorization(value = "Read - /{component-type}/{uuid} - For each component in the snippet and their descendant components", type = ""),
|
||||
@Authorization(value = "Write - if the snippet contains any restricted Processors - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
@ -1687,7 +1692,24 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
serviceFacade,
|
||||
requestCopySnippetEntity,
|
||||
lookup -> {
|
||||
authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), false);
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
final SnippetAuthorizable snippet = authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), false);
|
||||
|
||||
// flag to only perform the restricted check once, atomic reference so we can mark final and use in lambda
|
||||
final AtomicBoolean restrictedCheckPerformed = new AtomicBoolean(false);
|
||||
final Consumer<ConfigurableComponentAuthorizable> authorizeRestricted = authorizable -> {
|
||||
if (authorizable.isRestricted() && restrictedCheckPerformed.compareAndSet(false, true)) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
}
|
||||
};
|
||||
|
||||
// consider each processor. note - this request will not create new controller services so we do not need to check
|
||||
// for if there are not restricted controller services. it will however, need to authorize the user has access
|
||||
// to any referenced services and this is done within authorizeSnippetUsage above.
|
||||
snippet.getSelectedProcessors().stream().forEach(authorizeRestricted);
|
||||
snippet.getSelectedProcessGroups().stream().forEach(processGroup -> {
|
||||
processGroup.getEncapsulatedProcessors().forEach(authorizeRestricted);
|
||||
});
|
||||
},
|
||||
null,
|
||||
copySnippetRequestEntity -> {
|
||||
|
@ -1736,7 +1758,8 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
response = FlowEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||
@Authorization(value = "Read - /templates/{uuid}", type = "")
|
||||
@Authorization(value = "Read - /templates/{uuid}", type = ""),
|
||||
@Authorization(value = "Write - if the template contains any restricted components - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
@ -1773,11 +1796,27 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
serviceFacade,
|
||||
requestInstantiateTemplateRequestEntity,
|
||||
lookup -> {
|
||||
final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable();
|
||||
processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
|
||||
final Authorizable template = lookup.getTemplate(requestInstantiateTemplateRequestEntity.getTemplateId());
|
||||
template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
|
||||
// ensure write on the group
|
||||
final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable();
|
||||
processGroup.authorize(authorizer, RequestAction.WRITE, user);
|
||||
|
||||
// ensure read on the template
|
||||
final TemplateAuthorizable template = lookup.getTemplate(requestInstantiateTemplateRequestEntity.getTemplateId());
|
||||
template.getAuthorizable().authorize(authorizer, RequestAction.READ, user);
|
||||
|
||||
// flag to only perform the restricted check once, atomic reference so we can mark final and use in lambda
|
||||
final AtomicBoolean restrictedCheckPerformed = new AtomicBoolean(false);
|
||||
final Consumer<ConfigurableComponentAuthorizable> authorizeRestricted = authorizable -> {
|
||||
if (authorizable.isRestricted() && restrictedCheckPerformed.compareAndSet(false, true)) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
}
|
||||
};
|
||||
|
||||
// ensure restricted access if necessary
|
||||
template.getEncapsulatedProcessors().forEach(authorizeRestricted);
|
||||
template.getEncapsulatedControllerServices().forEach(authorizeRestricted);
|
||||
},
|
||||
null,
|
||||
instantiateTemplateRequestEntity -> {
|
||||
|
@ -1805,13 +1844,16 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
// templates
|
||||
// ---------
|
||||
|
||||
private void authorizeSnippetUsage(final AuthorizableLookup lookup, final String groupId, final String snippetId, final boolean authorizeTransitiveServices) {
|
||||
private SnippetAuthorizable authorizeSnippetUsage(final AuthorizableLookup lookup, final String groupId, final String snippetId, final boolean authorizeTransitiveServices) {
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
|
||||
// ensure write access to the target process group
|
||||
lookup.getProcessGroup(groupId).getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
lookup.getProcessGroup(groupId).getAuthorizable().authorize(authorizer, RequestAction.WRITE, user);
|
||||
|
||||
// ensure read permission to every component in the snippet including referenced services
|
||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||
final SnippetAuthorizable snippet = lookup.getSnippet(snippetId);
|
||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.READ, true, authorizeTransitiveServices);
|
||||
return snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2075,7 +2117,8 @@ public class ProcessGroupResource extends ApplicationResource {
|
|||
response = ControllerServiceEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
|
||||
@Authorization(value = "Write - if the Controller Service is restricted - /restricted-components", type = "")
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
|
|
|
@ -26,9 +26,9 @@ import org.apache.nifi.authorization.AccessDeniedException;
|
|||
import org.apache.nifi.authorization.AuthorizableLookup;
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.SnippetAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
import org.apache.nifi.web.NiFiServiceFacade;
|
||||
import org.apache.nifi.web.Revision;
|
||||
import org.apache.nifi.web.api.dto.SnippetDTO;
|
||||
|
@ -106,8 +106,8 @@ public class SnippetResource extends ApplicationResource {
|
|||
private void authorizeSnippetRequest(final SnippetDTO snippetRequest, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action) {
|
||||
final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
|
||||
|
||||
// note - we are not authorizing templates or controller services as they are not considered when using this snippet
|
||||
snippetRequest.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(processGroupAuthorizable -> {
|
||||
// note - we are not authorizing templates or controller services as they are not considered when using this snippet. additionally,
|
||||
// we are not checking referenced services since we do not know how this snippet will be used. these checks should be performed
|
||||
// in a subsequent action with this snippet
|
||||
authorizeProcessGroup(processGroupAuthorizable, authorizer, lookup, action, false, false, false, false);
|
||||
|
@ -116,8 +116,9 @@ public class SnippetResource extends ApplicationResource {
|
|||
snippetRequest.getProcessors().keySet().stream().map(id -> lookup.getProcessor(id).getAuthorizable()).forEach(authorize);
|
||||
snippetRequest.getInputPorts().keySet().stream().map(id -> lookup.getInputPort(id)).forEach(authorize);
|
||||
snippetRequest.getOutputPorts().keySet().stream().map(id -> lookup.getOutputPort(id)).forEach(authorize);
|
||||
snippetRequest.getConnections().keySet().stream().map(id -> lookup.getConnection(id)).forEach(connAuth -> authorize.accept(connAuth.getAuthorizable()));
|
||||
snippetRequest.getConnections().keySet().stream().map(id -> lookup.getConnection(id).getAuthorizable()).forEach(authorize);
|
||||
snippetRequest.getFunnels().keySet().stream().map(id -> lookup.getFunnel(id)).forEach(authorize);
|
||||
snippetRequest.getLabels().keySet().stream().map(id -> lookup.getLabel(id)).forEach(authorize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,6 +163,10 @@ public class SnippetResource extends ApplicationResource {
|
|||
throw new IllegalArgumentException("Snippet ID cannot be specified.");
|
||||
}
|
||||
|
||||
if (requestSnippetEntity.getSnippet().getParentGroupId() == null) {
|
||||
throw new IllegalArgumentException("The parent Process Group of the snippet must be specified.");
|
||||
}
|
||||
|
||||
if (isReplicateRequest()) {
|
||||
return replicate(HttpMethod.POST, requestSnippetEntity);
|
||||
}
|
||||
|
@ -268,7 +273,7 @@ public class SnippetResource extends ApplicationResource {
|
|||
}
|
||||
|
||||
// ensure write permission to every component in the snippet excluding referenced services
|
||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||
final SnippetAuthorizable snippet = lookup.getSnippet(snippetId);
|
||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE, false, false);
|
||||
},
|
||||
() -> serviceFacade.verifyUpdateSnippet(requestSnippetDTO, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
||||
|
@ -331,7 +336,7 @@ public class SnippetResource extends ApplicationResource {
|
|||
requestRevisions,
|
||||
lookup -> {
|
||||
// ensure write permission to every component in the snippet excluding referenced services
|
||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||
final SnippetAuthorizable snippet = lookup.getSnippet(snippetId);
|
||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE, true, false);
|
||||
},
|
||||
() -> serviceFacade.verifyDeleteSnippet(snippetId, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
||||
|
|
|
@ -122,7 +122,7 @@ public class TemplateResource extends ApplicationResource {
|
|||
|
||||
// authorize access
|
||||
serviceFacade.authorizeAccess(lookup -> {
|
||||
final Authorizable template = lookup.getTemplate(id);
|
||||
final Authorizable template = lookup.getTemplate(id).getAuthorizable();
|
||||
template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
|
||||
});
|
||||
|
||||
|
@ -196,7 +196,7 @@ public class TemplateResource extends ApplicationResource {
|
|||
serviceFacade,
|
||||
requestTemplateEntity,
|
||||
lookup -> {
|
||||
final Authorizable template = lookup.getTemplate(id);
|
||||
final Authorizable template = lookup.getTemplate(id).getAuthorizable();
|
||||
template.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
},
|
||||
null,
|
||||
|
|
|
@ -21,12 +21,21 @@ import org.apache.nifi.integration.util.NiFiTestAuthorizer;
|
|||
import org.apache.nifi.integration.util.NiFiTestUser;
|
||||
import org.apache.nifi.integration.util.RestrictedProcessor;
|
||||
import org.apache.nifi.integration.util.SourceTestProcessor;
|
||||
import org.apache.nifi.util.Tuple;
|
||||
import org.apache.nifi.web.api.dto.ProcessorDTO;
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
import org.apache.nifi.web.api.dto.SnippetDTO;
|
||||
import org.apache.nifi.web.api.dto.flow.FlowDTO;
|
||||
import org.apache.nifi.web.api.entity.CopySnippetRequestEntity;
|
||||
import org.apache.nifi.web.api.entity.CreateTemplateRequestEntity;
|
||||
import org.apache.nifi.web.api.entity.FlowEntity;
|
||||
import org.apache.nifi.web.api.entity.InstantiateTemplateRequestEntity;
|
||||
import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
|
||||
import org.apache.nifi.web.api.entity.ProcessorEntity;
|
||||
import org.apache.nifi.web.api.entity.SnippetEntity;
|
||||
import org.apache.nifi.web.api.entity.TemplateEntity;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -435,6 +444,187 @@ public class ITProcessorAccessControl {
|
|||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final ProcessorEntity responseEntity = response.getEntity(ProcessorEntity.class);
|
||||
|
||||
// remove the restricted component
|
||||
deleteRestrictedComponent(responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests attempting to copy/paste a restricted processor.
|
||||
*
|
||||
* @throws Exception ex
|
||||
*/
|
||||
@Test
|
||||
public void testCopyPasteRestrictedProcessor() throws Exception {
|
||||
final String copyUrl = helper.getBaseUrl() + "/process-groups/root/snippet-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent();
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// build the copy/paste request
|
||||
final CopySnippetRequestEntity copyRequest = new CopySnippetRequestEntity();
|
||||
copyRequest.setSnippetId(snippetEntity.getSnippet().getId());
|
||||
copyRequest.setOriginX(0.0);
|
||||
copyRequest.setOriginY(0.0);
|
||||
|
||||
// create the snippet
|
||||
ClientResponse response = helper.getReadWriteUser().testPost(copyUrl, copyRequest);
|
||||
|
||||
// ensure the request failed... need privileged users since snippet comprised of the restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getPrivilegedUser().testPost(copyUrl, copyRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final FlowEntity flowEntity = response.getEntity(FlowEntity.class);
|
||||
|
||||
// remove the restricted processors
|
||||
deleteRestrictedComponent(tuple.getKey());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests attempting to use a template with a restricted processor.
|
||||
*
|
||||
* @throws Exception ex
|
||||
*/
|
||||
@Test
|
||||
public void testTemplateWithRestrictedProcessor() throws Exception {
|
||||
final String createTemplateUrl = helper.getBaseUrl() + "/process-groups/root/templates";
|
||||
final String instantiateTemplateUrl = helper.getBaseUrl() + "/process-groups/root/template-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent();
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// create the template
|
||||
final CreateTemplateRequestEntity createTemplateRequest = new CreateTemplateRequestEntity();
|
||||
createTemplateRequest.setSnippetId(snippetEntity.getSnippet().getId());
|
||||
createTemplateRequest.setName("test");
|
||||
|
||||
// create the snippet
|
||||
ClientResponse response = helper.getWriteUser().testPost(createTemplateUrl, createTemplateRequest);
|
||||
|
||||
// ensure the request failed... need read perms to the components in the snippet
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
response = helper.getReadWriteUser().testPost(createTemplateUrl, createTemplateRequest);
|
||||
|
||||
// ensure the request is successfull
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final TemplateEntity templateEntity = response.getEntity(TemplateEntity.class);
|
||||
|
||||
// build the template request
|
||||
final InstantiateTemplateRequestEntity instantiateTemplateRequest = new InstantiateTemplateRequestEntity();
|
||||
instantiateTemplateRequest.setTemplateId(templateEntity.getTemplate().getId());
|
||||
instantiateTemplateRequest.setOriginX(0.0);
|
||||
instantiateTemplateRequest.setOriginY(0.0);
|
||||
|
||||
// create the snippet
|
||||
response = helper.getReadWriteUser().testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
// ensure the request failed... need privileged user since the template is comprised of restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getPrivilegedUser().testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final FlowEntity flowEntity = response.getEntity(FlowEntity.class);
|
||||
|
||||
// clean up the resources created during this test
|
||||
deleteTemplate(templateEntity);
|
||||
deleteRestrictedComponent(tuple.getKey());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
|
||||
}
|
||||
|
||||
private Tuple<ProcessorEntity, SnippetEntity> createSnippetWithRestrictedComponent() throws Exception {
|
||||
final String processorUrl = helper.getBaseUrl() + "/process-groups/root/processors";
|
||||
final String snippetUrl = helper.getBaseUrl() + "/snippets";
|
||||
|
||||
// create the processor
|
||||
ProcessorDTO processor = new ProcessorDTO();
|
||||
processor.setName("restricted");
|
||||
processor.setType(RestrictedProcessor.class.getName());
|
||||
|
||||
// create the revision
|
||||
final RevisionDTO revision = new RevisionDTO();
|
||||
revision.setClientId(READ_WRITE_CLIENT_ID);
|
||||
revision.setVersion(0L);
|
||||
|
||||
// create the entity body
|
||||
ProcessorEntity entity = new ProcessorEntity();
|
||||
entity.setRevision(revision);
|
||||
entity.setComponent(processor);
|
||||
|
||||
// perform the request as a user with read/write and restricted access
|
||||
ClientResponse response = helper.getPrivilegedUser().testPost(processorUrl, entity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
// get the response
|
||||
final ProcessorEntity responseProcessorEntity = response.getEntity(ProcessorEntity.class);
|
||||
|
||||
// build the snippet for the copy/paste
|
||||
final SnippetDTO snippet = new SnippetDTO();
|
||||
snippet.setParentGroupId(responseProcessorEntity.getComponent().getParentGroupId());
|
||||
snippet.getProcessors().put(responseProcessorEntity.getId(), responseProcessorEntity.getRevision());
|
||||
|
||||
// create the entity body
|
||||
final SnippetEntity snippetEntity = new SnippetEntity();
|
||||
snippetEntity.setSnippet(snippet);
|
||||
|
||||
// create the snippet
|
||||
response = helper.getNoneUser().testPost(snippetUrl, snippetEntity);
|
||||
|
||||
// ensure the request failed... need either read or write to create snippet (not sure what snippet will be used for)
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getReadWriteUser().testPost(snippetUrl, snippetEntity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
// get the response
|
||||
return new Tuple<>(responseProcessorEntity, response.getEntity(SnippetEntity.class));
|
||||
}
|
||||
|
||||
private void deleteTemplate(final TemplateEntity entity) throws Exception {
|
||||
// perform the request
|
||||
ClientResponse response = helper.getReadWriteUser().testDelete(entity.getTemplate().getUri());
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
private void deleteRestrictedComponent(final ProcessorEntity entity) throws Exception {
|
||||
if (entity == null) {
|
||||
Assert.fail("Failed to get Processor from template or snippet request.");
|
||||
return;
|
||||
}
|
||||
|
||||
// create the entity body
|
||||
final Map<String, String> queryParams = new HashMap<>();
|
||||
queryParams.put("version", String.valueOf(entity.getRevision().getVersion()));
|
||||
queryParams.put("clientId", READ_WRITE_CLIENT_ID);
|
||||
|
||||
// perform the request
|
||||
ClientResponse response = helper.getReadWriteUser().testDelete(entity.getUri(), queryParams);
|
||||
|
||||
// ensure the request fails... needs access to restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
response = helper.getPrivilegedUser().testDelete(entity.getUri(), queryParams);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
private ProcessorEntity getRandomProcessor(final NiFiTestUser user) throws Exception {
|
||||
|
|
|
@ -13,4 +13,5 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
org.apache.nifi.integration.util.SourceTestProcessor
|
||||
org.apache.nifi.integration.util.TerminationTestProcessor
|
||||
org.apache.nifi.integration.util.TerminationTestProcessor
|
||||
org.apache.nifi.integration.util.RestrictedProcessor
|
Loading…
Reference in New Issue