mirror of https://github.com/apache/nifi.git
NIFI-3117: - Checking referenced services when performing an action with a snippet that requires it.
- Updating the SnippetManager to automatically expire unused snippets. - Making the checking of referenced services consistent across component removal. - Adding checking of referenced services for all nested components in a snippet. - Updating the REST API docs to clarify when a referenced service is authorized. - Conditionally authorizing transitive service references. This closes #1277. Signed-off-by: Bryan Bende <bbende@apache.org>
This commit is contained in:
parent
e3c7611347
commit
bc223fa197
|
@ -16,49 +16,52 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.controller;
|
package org.apache.nifi.controller;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import org.apache.nifi.persistence.StandardSnippetDeserializer;
|
||||||
|
import org.apache.nifi.persistence.StandardSnippetSerializer;
|
||||||
|
import org.apache.nifi.stream.io.ByteArrayInputStream;
|
||||||
|
import org.apache.nifi.stream.io.ByteArrayOutputStream;
|
||||||
|
import org.apache.nifi.stream.io.DataOutputStream;
|
||||||
|
import org.apache.nifi.stream.io.StreamUtils;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import org.apache.nifi.stream.io.ByteArrayInputStream;
|
|
||||||
import org.apache.nifi.stream.io.ByteArrayOutputStream;
|
|
||||||
import org.apache.nifi.stream.io.DataOutputStream;
|
|
||||||
import org.apache.nifi.stream.io.StreamUtils;
|
|
||||||
import org.apache.nifi.persistence.StandardSnippetDeserializer;
|
|
||||||
import org.apache.nifi.persistence.StandardSnippetSerializer;
|
|
||||||
|
|
||||||
public class SnippetManager {
|
public class SnippetManager {
|
||||||
|
|
||||||
private final ConcurrentMap<String, StandardSnippet> snippetMap = new ConcurrentHashMap<>();
|
private final Cache<String, StandardSnippet> snippetMap = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||||
|
|
||||||
public void addSnippet(final StandardSnippet snippet) {
|
public synchronized void addSnippet(final StandardSnippet snippet) {
|
||||||
final StandardSnippet oldSnippet = this.snippetMap.putIfAbsent(snippet.getId(), snippet);
|
if (snippetMap.getIfPresent(snippet.getId()) != null) {
|
||||||
if (oldSnippet != null) {
|
|
||||||
throw new IllegalStateException("Snippet with ID " + snippet.getId() + " already exists");
|
throw new IllegalStateException("Snippet with ID " + snippet.getId() + " already exists");
|
||||||
}
|
}
|
||||||
|
snippetMap.put(snippet.getId(), snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSnippet(final StandardSnippet snippet) {
|
public synchronized void removeSnippet(final StandardSnippet snippet) {
|
||||||
if (!snippetMap.remove(snippet.getId(), snippet)) {
|
if (snippetMap.getIfPresent(snippet.getId()) == null) {
|
||||||
throw new IllegalStateException("Snippet is not contained in this SnippetManager");
|
throw new IllegalStateException("Snippet is not contained in this SnippetManager");
|
||||||
}
|
}
|
||||||
|
snippetMap.invalidate(snippet.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public StandardSnippet getSnippet(final String identifier) {
|
public synchronized StandardSnippet getSnippet(final String identifier) {
|
||||||
return snippetMap.get(identifier);
|
return snippetMap.getIfPresent(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<StandardSnippet> getSnippets() {
|
public synchronized Collection<StandardSnippet> getSnippets() {
|
||||||
return snippetMap.values();
|
return Collections.unmodifiableCollection(snippetMap.asMap().values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public synchronized void clear() {
|
||||||
snippetMap.clear();
|
snippetMap.invalidateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<StandardSnippet> parseBytes(final byte[] bytes) {
|
public static List<StandardSnippet> parseBytes(final byte[] bytes) {
|
||||||
|
|
|
@ -30,6 +30,40 @@ import java.util.Objects;
|
||||||
*/
|
*/
|
||||||
public final class AuthorizeControllerServiceReference {
|
public final class AuthorizeControllerServiceReference {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorizes any referenced controller services from the specified configurable component.
|
||||||
|
*
|
||||||
|
* @param authorizable authorizable that may reference a controller service
|
||||||
|
* @param authorizer authorizer
|
||||||
|
* @param lookup lookup
|
||||||
|
*/
|
||||||
|
public static void authorizeControllerServiceReferences(final ConfigurableComponentAuthorizable authorizable, final Authorizer authorizer,
|
||||||
|
final AuthorizableLookup lookup, final boolean authorizeTransitiveServices) {
|
||||||
|
|
||||||
|
// consider each property when looking for service references
|
||||||
|
authorizable.getPropertyDescriptors().stream().forEach(descriptor -> {
|
||||||
|
// if this descriptor identifies a controller service
|
||||||
|
if (descriptor.getControllerServiceDefinition() != null) {
|
||||||
|
// get the service id
|
||||||
|
final String serviceId = authorizable.getValue(descriptor);
|
||||||
|
|
||||||
|
// authorize the service if configured
|
||||||
|
if (serviceId != null) {
|
||||||
|
try {
|
||||||
|
final ConfigurableComponentAuthorizable currentServiceAuthorizable = lookup.getControllerService(serviceId);
|
||||||
|
currentServiceAuthorizable.getAuthorizable().authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
|
if (authorizeTransitiveServices) {
|
||||||
|
authorizeControllerServiceReferences(currentServiceAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||||
|
}
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
// ignore if the resource is not found, if the referenced service was previously deleted, it should not stop this action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorizes the proposed properties for the specified authorizable.
|
* Authorizes the proposed properties for the specified authorizable.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.apache.nifi.authorization;
|
||||||
import org.apache.nifi.authorization.resource.Authorizable;
|
import org.apache.nifi.authorization.resource.Authorizable;
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorizable for a component that references a ControllerService.
|
* Authorizable for a component that references a ControllerService.
|
||||||
*/
|
*/
|
||||||
|
@ -45,6 +47,13 @@ public interface ConfigurableComponentAuthorizable {
|
||||||
*/
|
*/
|
||||||
PropertyDescriptor getPropertyDescriptor(String propertyName);
|
PropertyDescriptor getPropertyDescriptor(String propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the property descriptors for this configurable component.
|
||||||
|
*
|
||||||
|
* @return property descriptors
|
||||||
|
*/
|
||||||
|
List<PropertyDescriptor> getPropertyDescriptors();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current value of the specified property.
|
* Returns the current value of the specified property.
|
||||||
*
|
*
|
||||||
|
|
|
@ -32,9 +32,73 @@ public interface ProcessGroupAuthorizable {
|
||||||
Authorizable getAuthorizable();
|
Authorizable getAuthorizable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The authorizables for all encapsulated components. Non null
|
* The authorizables for all encapsulated processors. Non null
|
||||||
*
|
*
|
||||||
* @return all encapsulated authorizables
|
* @return all encapsulated processors
|
||||||
*/
|
*/
|
||||||
Set<Authorizable> getEncapsulatedAuthorizables();
|
Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated connections. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated connections
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedConnections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated input ports. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated input ports
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedInputPorts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated output ports. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated output ports
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedOutputPorts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated funnels. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated funnels
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedFunnels();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated labels. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated labels
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedLabels();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated process groups. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated process groups
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedProcessGroups();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated remote process groups. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated remote process groups
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedRemoteProcessGroups();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated templates. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated templates
|
||||||
|
*/
|
||||||
|
Set<Authorizable> getEncapsulatedTemplates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authorizables for all encapsulated input ports. Non null
|
||||||
|
*
|
||||||
|
* @return all encapsulated input ports
|
||||||
|
*/
|
||||||
|
Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,9 @@ import org.apache.nifi.web.dao.ReportingTaskDAO;
|
||||||
import org.apache.nifi.web.dao.SnippetDAO;
|
import org.apache.nifi.web.dao.SnippetDAO;
|
||||||
import org.apache.nifi.web.dao.TemplateDAO;
|
import org.apache.nifi.web.dao.TemplateDAO;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.List;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
class StandardAuthorizableLookup implements AuthorizableLookup {
|
class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
|
@ -139,54 +139,14 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getProcessor(final String id) {
|
public ConfigurableComponentAuthorizable getProcessor(final String id) {
|
||||||
final ProcessorNode processorNode = processorDAO.getProcessor(id);
|
final ProcessorNode processorNode = processorDAO.getProcessor(id);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ProcessorConfigurableComponentAuthorizable(processorNode);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return processorNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return processorNode.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return processorNode.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return processorNode.getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getProcessorByType(String type) {
|
public ConfigurableComponentAuthorizable getProcessorByType(String type) {
|
||||||
try {
|
try {
|
||||||
final ProcessorNode processorNode = controllerFacade.createTemporaryProcessor(type);
|
final ProcessorNode processorNode = controllerFacade.createTemporaryProcessor(type);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ProcessorConfigurableComponentAuthorizable(processorNode);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return processorNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return processorNode.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return processorNode.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return processorNode.getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new AccessDeniedException("Unable to create processor to verify if it references any Controller Services.");
|
throw new AccessDeniedException("Unable to create processor to verify if it references any Controller Services.");
|
||||||
}
|
}
|
||||||
|
@ -288,18 +248,6 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
public ProcessGroupAuthorizable getProcessGroup(final String id) {
|
public ProcessGroupAuthorizable getProcessGroup(final String id) {
|
||||||
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(id);
|
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(id);
|
||||||
|
|
||||||
final Set<Authorizable> encapsulatedAuthorizables = new HashSet<>();
|
|
||||||
processGroup.findAllProcessors().forEach(processor -> encapsulatedAuthorizables.add(processor));
|
|
||||||
processGroup.findAllConnections().forEach(connection -> encapsulatedAuthorizables.add(connection));
|
|
||||||
processGroup.findAllInputPorts().forEach(inputPort -> encapsulatedAuthorizables.add(inputPort));
|
|
||||||
processGroup.findAllOutputPorts().forEach(outputPort -> encapsulatedAuthorizables.add(outputPort));
|
|
||||||
processGroup.findAllFunnels().forEach(funnel -> encapsulatedAuthorizables.add(funnel));
|
|
||||||
processGroup.findAllLabels().forEach(label -> encapsulatedAuthorizables.add(label));
|
|
||||||
processGroup.findAllProcessGroups().forEach(childGroup -> encapsulatedAuthorizables.add(childGroup));
|
|
||||||
processGroup.findAllRemoteProcessGroups().forEach(remoteProcessGroup -> encapsulatedAuthorizables.add(remoteProcessGroup));
|
|
||||||
processGroup.findAllTemplates().forEach(template -> encapsulatedAuthorizables.add(template));
|
|
||||||
processGroup.findAllControllerServices().forEach(controllerService -> encapsulatedAuthorizables.add(controllerService));
|
|
||||||
|
|
||||||
return new ProcessGroupAuthorizable() {
|
return new ProcessGroupAuthorizable() {
|
||||||
@Override
|
@Override
|
||||||
public Authorizable getAuthorizable() {
|
public Authorizable getAuthorizable() {
|
||||||
|
@ -307,8 +255,55 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Authorizable> getEncapsulatedAuthorizables() {
|
public Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors() {
|
||||||
return Collections.unmodifiableSet(encapsulatedAuthorizables);
|
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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -343,54 +338,14 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getControllerService(final String id) {
|
public ConfigurableComponentAuthorizable getControllerService(final String id) {
|
||||||
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(id);
|
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(id);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ControllerServiceConfigurableComponentAuthorizable(controllerService);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return controllerService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return controllerService.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return controllerService.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return controllerService.getControllerServiceImplementation().getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getControllerServiceByType(String type) {
|
public ConfigurableComponentAuthorizable getControllerServiceByType(String type) {
|
||||||
try {
|
try {
|
||||||
final ControllerServiceNode controllerService = controllerFacade.createTemporaryControllerService(type);
|
final ControllerServiceNode controllerService = controllerFacade.createTemporaryControllerService(type);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ControllerServiceConfigurableComponentAuthorizable(controllerService);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return controllerService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return controllerService.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return controllerService.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return controllerService.getControllerServiceImplementation().getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new AccessDeniedException("Unable to create controller service to verify if it references any Controller Services.");
|
throw new AccessDeniedException("Unable to create controller service to verify if it references any Controller Services.");
|
||||||
}
|
}
|
||||||
|
@ -442,54 +397,14 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getReportingTask(final String id) {
|
public ConfigurableComponentAuthorizable getReportingTask(final String id) {
|
||||||
final ReportingTaskNode reportingTaskNode = reportingTaskDAO.getReportingTask(id);
|
final ReportingTaskNode reportingTaskNode = reportingTaskDAO.getReportingTask(id);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ReportingTaskConfigurableComponentAuthorizable(reportingTaskNode);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return reportingTaskNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return reportingTaskNode.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return reportingTaskNode.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return reportingTaskNode.getReportingTask().getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableComponentAuthorizable getReportingTaskByType(String type) {
|
public ConfigurableComponentAuthorizable getReportingTaskByType(String type) {
|
||||||
try {
|
try {
|
||||||
final ReportingTaskNode reportingTask = controllerFacade.createTemporaryReportingTask(type);
|
final ReportingTaskNode reportingTask = controllerFacade.createTemporaryReportingTask(type);
|
||||||
return new ConfigurableComponentAuthorizable() {
|
return new ReportingTaskConfigurableComponentAuthorizable(reportingTask);
|
||||||
@Override
|
|
||||||
public Authorizable getAuthorizable() {
|
|
||||||
return reportingTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRestricted() {
|
|
||||||
return reportingTask.isRestricted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
|
||||||
return reportingTask.getProperty(propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
|
||||||
return reportingTask.getReportingTask().getPropertyDescriptor(propertyName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
throw new AccessDeniedException("Unable to create reporting to verify if it references any Controller Services.");
|
throw new AccessDeniedException("Unable to create reporting to verify if it references any Controller Services.");
|
||||||
}
|
}
|
||||||
|
@ -730,6 +645,114 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||||
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigurableComponentAuthorizable for a ProcessorNode.
|
||||||
|
*/
|
||||||
|
private static class ProcessorConfigurableComponentAuthorizable implements ConfigurableComponentAuthorizable {
|
||||||
|
private final ProcessorNode processorNode;
|
||||||
|
|
||||||
|
public ProcessorConfigurableComponentAuthorizable(ProcessorNode processorNode) {
|
||||||
|
this.processorNode = processorNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authorizable getAuthorizable() {
|
||||||
|
return processorNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRestricted() {
|
||||||
|
return processorNode.isRestricted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||||
|
return processorNode.getProperty(propertyDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
||||||
|
return processorNode.getPropertyDescriptor(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PropertyDescriptor> getPropertyDescriptors() {
|
||||||
|
return processorNode.getPropertyDescriptors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigurableComponentAuthorizable for a ControllerServiceNode.
|
||||||
|
*/
|
||||||
|
private static class ControllerServiceConfigurableComponentAuthorizable implements ConfigurableComponentAuthorizable {
|
||||||
|
private final ControllerServiceNode controllerServiceNode;
|
||||||
|
|
||||||
|
public ControllerServiceConfigurableComponentAuthorizable(ControllerServiceNode controllerServiceNode) {
|
||||||
|
this.controllerServiceNode = controllerServiceNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authorizable getAuthorizable() {
|
||||||
|
return controllerServiceNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRestricted() {
|
||||||
|
return controllerServiceNode.isRestricted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||||
|
return controllerServiceNode.getProperty(propertyDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
||||||
|
return controllerServiceNode.getControllerServiceImplementation().getPropertyDescriptor(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PropertyDescriptor> getPropertyDescriptors() {
|
||||||
|
return controllerServiceNode.getControllerServiceImplementation().getPropertyDescriptors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigurableComponentAuthorizable for a ProcessorNode.
|
||||||
|
*/
|
||||||
|
private static class ReportingTaskConfigurableComponentAuthorizable implements ConfigurableComponentAuthorizable {
|
||||||
|
private final ReportingTaskNode reportingTaskNode;
|
||||||
|
|
||||||
|
public ReportingTaskConfigurableComponentAuthorizable(ReportingTaskNode reportingTaskNode) {
|
||||||
|
this.reportingTaskNode = reportingTaskNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authorizable getAuthorizable() {
|
||||||
|
return reportingTaskNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRestricted() {
|
||||||
|
return reportingTaskNode.isRestricted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||||
|
return reportingTaskNode.getProperty(propertyDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyDescriptor getPropertyDescriptor(String propertyName) {
|
||||||
|
return reportingTaskNode.getReportingTask().getPropertyDescriptor(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PropertyDescriptor> getPropertyDescriptors() {
|
||||||
|
return reportingTaskNode.getReportingTask().getPropertyDescriptors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authorizable getSystem() {
|
public Authorizable getSystem() {
|
||||||
return SYSTEM_AUTHORIZABLE;
|
return SYSTEM_AUTHORIZABLE;
|
||||||
|
|
|
@ -16,43 +16,18 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.web.api;
|
package org.apache.nifi.web.api;
|
||||||
|
|
||||||
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
|
import com.google.common.cache.Cache;
|
||||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTENT_NAME;
|
import com.sun.jersey.api.core.HttpContext;
|
||||||
import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTENT_VALUE;
|
import com.sun.jersey.api.representation.Form;
|
||||||
|
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
||||||
import java.net.URI;
|
import com.sun.jersey.server.impl.model.method.dispatch.FormDispatchProvider;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.ws.rs.core.CacheControl;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
|
||||||
import javax.ws.rs.core.UriBuilder;
|
|
||||||
import javax.ws.rs.core.UriBuilderException;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.nifi.authorization.AuthorizableLookup;
|
import org.apache.nifi.authorization.AuthorizableLookup;
|
||||||
import org.apache.nifi.authorization.AuthorizeAccess;
|
import org.apache.nifi.authorization.AuthorizeAccess;
|
||||||
|
import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
|
import org.apache.nifi.authorization.ProcessGroupAuthorizable;
|
||||||
import org.apache.nifi.authorization.RequestAction;
|
import org.apache.nifi.authorization.RequestAction;
|
||||||
import org.apache.nifi.authorization.resource.Authorizable;
|
import org.apache.nifi.authorization.resource.Authorizable;
|
||||||
import org.apache.nifi.authorization.user.NiFiUser;
|
import org.apache.nifi.authorization.user.NiFiUser;
|
||||||
|
@ -78,7 +53,6 @@ import org.apache.nifi.util.NiFiProperties;
|
||||||
import org.apache.nifi.web.NiFiServiceFacade;
|
import org.apache.nifi.web.NiFiServiceFacade;
|
||||||
import org.apache.nifi.web.Revision;
|
import org.apache.nifi.web.Revision;
|
||||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||||
import org.apache.nifi.web.api.dto.SnippetDTO;
|
|
||||||
import org.apache.nifi.web.api.entity.ComponentEntity;
|
import org.apache.nifi.web.api.entity.ComponentEntity;
|
||||||
import org.apache.nifi.web.api.entity.Entity;
|
import org.apache.nifi.web.api.entity.Entity;
|
||||||
import org.apache.nifi.web.api.entity.TransactionResultEntity;
|
import org.apache.nifi.web.api.entity.TransactionResultEntity;
|
||||||
|
@ -87,12 +61,37 @@ import org.apache.nifi.web.security.util.CacheKey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import com.sun.jersey.api.core.HttpContext;
|
import javax.ws.rs.core.CacheControl;
|
||||||
import com.sun.jersey.api.representation.Form;
|
import javax.ws.rs.core.Context;
|
||||||
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
import javax.ws.rs.core.MediaType;
|
||||||
import com.sun.jersey.server.impl.model.method.dispatch.FormDispatchProvider;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
import javax.ws.rs.core.UriBuilderException;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||||
|
import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTENT_NAME;
|
||||||
|
import static org.apache.nifi.remote.protocol.http.HttpHeaders.LOCATION_URI_INTENT_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for controllers.
|
* Base class for controllers.
|
||||||
|
@ -434,28 +433,60 @@ public abstract class ApplicationResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorizes the specified Snippet with the specified request action.
|
* Authorizes the specified process group.
|
||||||
*
|
*
|
||||||
* @param authorizer authorizer
|
* @param processGroupAuthorizable process group
|
||||||
* @param lookup lookup
|
* @param authorizer authorizer
|
||||||
* @param action action
|
* @param lookup lookup
|
||||||
|
* @param action action
|
||||||
|
* @param authorizeReferencedServices whether to authorize referenced services
|
||||||
|
* @param authorizeTemplates whether to authorize templates
|
||||||
|
* @param authorizeControllerServices whether to authorize controller services
|
||||||
*/
|
*/
|
||||||
protected void authorizeSnippet(final Snippet snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action) {
|
protected void authorizeProcessGroup(final ProcessGroupAuthorizable processGroupAuthorizable, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action,
|
||||||
|
final boolean authorizeReferencedServices, final boolean authorizeTemplates,
|
||||||
|
final boolean authorizeControllerServices, final boolean authorizeTransitiveServices) {
|
||||||
|
|
||||||
final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
|
final Consumer<Authorizable> authorize = authorizable -> authorizable.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
snippet.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(processGroupAuthorizable -> {
|
// authorize the process group
|
||||||
// authorize the process group
|
authorize.accept(processGroupAuthorizable.getAuthorizable());
|
||||||
authorize.accept(processGroupAuthorizable.getAuthorizable());
|
|
||||||
|
|
||||||
// authorize the contents of the group
|
// authorize the contents of the group - these methods return all encapsulated components (recursive)
|
||||||
processGroupAuthorizable.getEncapsulatedAuthorizables().forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedProcessors().forEach(processorAuthorizable -> {
|
||||||
|
// authorize the processor
|
||||||
|
authorize.accept(processorAuthorizable.getAuthorizable());
|
||||||
|
|
||||||
|
// authorize any referenced services if necessary
|
||||||
|
if (authorizeReferencedServices) {
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(processorAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedConnections().forEach(authorize);
|
||||||
snippet.getProcessors().keySet().stream().map(id -> lookup.getProcessor(id).getAuthorizable()).forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedInputPorts().forEach(authorize);
|
||||||
snippet.getInputPorts().keySet().stream().map(id -> lookup.getInputPort(id)).forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedOutputPorts().forEach(authorize);
|
||||||
snippet.getOutputPorts().keySet().stream().map(id -> lookup.getOutputPort(id)).forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedFunnels().forEach(authorize);
|
||||||
snippet.getConnections().keySet().stream().map(id -> lookup.getConnection(id)).forEach(connAuth -> authorize.accept(connAuth.getAuthorizable()));
|
processGroupAuthorizable.getEncapsulatedLabels().forEach(authorize);
|
||||||
snippet.getFunnels().keySet().stream().map(id -> lookup.getFunnel(id)).forEach(authorize);
|
processGroupAuthorizable.getEncapsulatedProcessGroups().forEach(authorize);
|
||||||
|
processGroupAuthorizable.getEncapsulatedRemoteProcessGroups().forEach(authorize);
|
||||||
|
|
||||||
|
// authorize templates if necessary
|
||||||
|
if (authorizeTemplates) {
|
||||||
|
processGroupAuthorizable.getEncapsulatedTemplates().forEach(authorize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// authorize controller services if necessary
|
||||||
|
if (authorizeControllerServices) {
|
||||||
|
processGroupAuthorizable.getEncapsulatedControllerServices().forEach(controllerServiceAuthorizable -> {
|
||||||
|
// authorize the controller service
|
||||||
|
authorize.accept(controllerServiceAuthorizable.getAuthorizable());
|
||||||
|
|
||||||
|
// authorize any referenced services if necessary
|
||||||
|
if (authorizeReferencedServices) {
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(controllerServiceAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -465,18 +496,26 @@ public abstract class ApplicationResource {
|
||||||
* @param lookup lookup
|
* @param lookup lookup
|
||||||
* @param action action
|
* @param action action
|
||||||
*/
|
*/
|
||||||
protected void authorizeSnippet(final SnippetDTO snippet, final Authorizer authorizer, final AuthorizableLookup lookup, final RequestAction action) {
|
protected void authorizeSnippet(final Snippet 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());
|
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.getProcessGroups().keySet().stream().map(id -> lookup.getProcessGroup(id)).forEach(processGroupAuthorizable -> {
|
||||||
// authorize the process group
|
// note - we are not authorizing templates or controller services as they are not considered when using this snippet. however,
|
||||||
authorize.accept(processGroupAuthorizable.getAuthorizable());
|
// referenced services are considered so those are explicitly authorized when authorizing a processor
|
||||||
|
authorizeProcessGroup(processGroupAuthorizable, authorizer, lookup, action, authorizeReferencedServices, false, false, authorizeTransitiveServices);
|
||||||
// authorize the contents of the group
|
|
||||||
processGroupAuthorizable.getEncapsulatedAuthorizables().forEach(authorize);
|
|
||||||
});
|
});
|
||||||
snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
|
snippet.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
|
||||||
snippet.getProcessors().keySet().stream().map(id -> lookup.getProcessor(id).getAuthorizable()).forEach(authorize);
|
snippet.getProcessors().keySet().stream().map(id -> lookup.getProcessor(id)).forEach(processorAuthorizable -> {
|
||||||
|
// authorize the processor
|
||||||
|
authorize.accept(processorAuthorizable.getAuthorizable());
|
||||||
|
|
||||||
|
// authorize any referenced services if necessary
|
||||||
|
if (authorizeReferencedServices) {
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(processorAuthorizable, authorizer, lookup, authorizeTransitiveServices);
|
||||||
|
}
|
||||||
|
});
|
||||||
snippet.getInputPorts().keySet().stream().map(id -> lookup.getInputPort(id)).forEach(authorize);
|
snippet.getInputPorts().keySet().stream().map(id -> lookup.getInputPort(id)).forEach(authorize);
|
||||||
snippet.getOutputPorts().keySet().stream().map(id -> lookup.getOutputPort(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.getConnections().keySet().stream().map(id -> lookup.getConnection(id)).forEach(connAuth -> authorize.accept(connAuth.getAuthorizable()));
|
||||||
|
|
|
@ -570,7 +570,7 @@ public class ControllerServiceResource extends ApplicationResource {
|
||||||
response = ControllerServiceEntity.class,
|
response = ControllerServiceEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /controller-services/{uuid}", type = ""),
|
@Authorization(value = "Write - /controller-services/{uuid}", type = ""),
|
||||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
@Authorization(value = "Read - any referenced Controller Services if this request changes the reference - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -660,7 +660,8 @@ public class ControllerServiceResource extends ApplicationResource {
|
||||||
value = "Deletes a controller service",
|
value = "Deletes a controller service",
|
||||||
response = ControllerServiceEntity.class,
|
response = ControllerServiceEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /controller-services/{uuid}", type = "")
|
@Authorization(value = "Write - /controller-services/{uuid}", type = ""),
|
||||||
|
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -704,8 +705,11 @@ public class ControllerServiceResource extends ApplicationResource {
|
||||||
requestControllerServiceEntity,
|
requestControllerServiceEntity,
|
||||||
requestRevision,
|
requestRevision,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
final Authorizable controllerService = lookup.getControllerService(id).getAuthorizable();
|
final ConfigurableComponentAuthorizable controllerService = lookup.getControllerService(id);
|
||||||
controllerService.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
controllerService.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
|
// verify any referenced services
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(controllerService, authorizer, lookup, false);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyDeleteControllerService(id),
|
() -> serviceFacade.verifyDeleteControllerService(id),
|
||||||
(revision, controllerServiceEntity) -> {
|
(revision, controllerServiceEntity) -> {
|
||||||
|
|
|
@ -373,14 +373,9 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||||
final ProcessGroupAuthorizable processGroupAuthorizable = lookup.getProcessGroup(id);
|
final ProcessGroupAuthorizable processGroupAuthorizable = lookup.getProcessGroup(id);
|
||||||
|
|
||||||
// ensure write to the process group
|
// ensure write to this process group and all encapsulated components including templates and controller services. additionally, ensure
|
||||||
final Authorizable processGroup = processGroupAuthorizable.getAuthorizable();
|
// read to any referenced services by encapsulated components
|
||||||
processGroup.authorize(authorizer, RequestAction.WRITE, user);
|
authorizeProcessGroup(processGroupAuthorizable, authorizer, lookup, RequestAction.WRITE, true, true, true, false);
|
||||||
|
|
||||||
// ensure write to all encapsulated components
|
|
||||||
processGroupAuthorizable.getEncapsulatedAuthorizables().forEach(encaupsulatedAuthorizable -> {
|
|
||||||
encaupsulatedAuthorizable.authorize(authorizer, RequestAction.WRITE, user);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyDeleteProcessGroup(id),
|
() -> serviceFacade.verifyDeleteProcessGroup(id),
|
||||||
(revision, processGroupEntity) -> {
|
(revision, processGroupEntity) -> {
|
||||||
|
@ -1647,7 +1642,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("{id}/snippet-instance")
|
@Path("{id}/snippet-instance")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Copies a snippet",
|
value = "Copies a snippet and discards it.",
|
||||||
response = FlowSnippetEntity.class,
|
response = FlowSnippetEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||||
|
@ -1692,7 +1687,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
serviceFacade,
|
serviceFacade,
|
||||||
requestCopySnippetEntity,
|
requestCopySnippetEntity,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId());
|
authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), false);
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
copySnippetRequestEntity -> {
|
copySnippetRequestEntity -> {
|
||||||
|
@ -1810,13 +1805,13 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
// templates
|
// templates
|
||||||
// ---------
|
// ---------
|
||||||
|
|
||||||
private void authorizeSnippetUsage(final AuthorizableLookup lookup, final String groupId, final String snippetId) {
|
private void authorizeSnippetUsage(final AuthorizableLookup lookup, final String groupId, final String snippetId, final boolean authorizeTransitiveServices) {
|
||||||
// ensure write access to the target process group
|
// 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, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
// ensure read permission to every component in the snippet
|
// ensure read permission to every component in the snippet including referenced services
|
||||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.READ);
|
authorizeSnippet(snippet, authorizer, lookup, RequestAction.READ, true, authorizeTransitiveServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1831,7 +1826,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("{id}/templates")
|
@Path("{id}/templates")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Creates a template",
|
value = "Creates a template and discards the specified snippet.",
|
||||||
response = TemplateEntity.class,
|
response = TemplateEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
@Authorization(value = "Write - /process-groups/{uuid}", type = ""),
|
||||||
|
@ -1871,7 +1866,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||||
serviceFacade,
|
serviceFacade,
|
||||||
requestCreateTemplateRequestEntity,
|
requestCreateTemplateRequestEntity,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
authorizeSnippetUsage(lookup, groupId, requestCreateTemplateRequestEntity.getSnippetId());
|
authorizeSnippetUsage(lookup, groupId, requestCreateTemplateRequestEntity.getSnippetId(), true);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyCanAddTemplate(groupId, requestCreateTemplateRequestEntity.getName()),
|
() -> serviceFacade.verifyCanAddTemplate(groupId, requestCreateTemplateRequestEntity.getName()),
|
||||||
createTemplateRequestEntity -> {
|
createTemplateRequestEntity -> {
|
||||||
|
|
|
@ -396,7 +396,7 @@ public class ProcessorResource extends ApplicationResource {
|
||||||
response = ProcessorEntity.class,
|
response = ProcessorEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /processors/{uuid}", type = ""),
|
@Authorization(value = "Write - /processors/{uuid}", type = ""),
|
||||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
@Authorization(value = "Read - any referenced Controller Services if this request changes the reference - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -487,7 +487,8 @@ public class ProcessorResource extends ApplicationResource {
|
||||||
value = "Deletes a processor",
|
value = "Deletes a processor",
|
||||||
response = ProcessorEntity.class,
|
response = ProcessorEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /processors/{uuid}", type = "")
|
@Authorization(value = "Write - /processors/{uuid}", type = ""),
|
||||||
|
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -530,8 +531,11 @@ public class ProcessorResource extends ApplicationResource {
|
||||||
requestProcessorEntity,
|
requestProcessorEntity,
|
||||||
requestRevision,
|
requestRevision,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
final Authorizable processor = lookup.getProcessor(id).getAuthorizable();
|
final ConfigurableComponentAuthorizable processor = lookup.getProcessor(id);
|
||||||
processor.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
processor.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
|
// verify any referenced services
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(processor, authorizer, lookup, false);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyDeleteProcessor(id),
|
() -> serviceFacade.verifyDeleteProcessor(id),
|
||||||
(revision, processorEntity) -> {
|
(revision, processorEntity) -> {
|
||||||
|
|
|
@ -374,7 +374,7 @@ public class ReportingTaskResource extends ApplicationResource {
|
||||||
response = ReportingTaskEntity.class,
|
response = ReportingTaskEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /reporting-tasks/{uuid}", type = ""),
|
@Authorization(value = "Write - /reporting-tasks/{uuid}", type = ""),
|
||||||
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
@Authorization(value = "Read - any referenced Controller Services if this request changes the reference - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -464,7 +464,8 @@ public class ReportingTaskResource extends ApplicationResource {
|
||||||
value = "Deletes a reporting task",
|
value = "Deletes a reporting task",
|
||||||
response = ReportingTaskEntity.class,
|
response = ReportingTaskEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /reporting-tasks/{uuid}", type = "")
|
@Authorization(value = "Write - /reporting-tasks/{uuid}", type = ""),
|
||||||
|
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = "")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
@ -508,8 +509,11 @@ public class ReportingTaskResource extends ApplicationResource {
|
||||||
requestReportingTaskEntity,
|
requestReportingTaskEntity,
|
||||||
requestRevision,
|
requestRevision,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
final Authorizable reportingTask = lookup.getReportingTask(id).getAuthorizable();
|
final ConfigurableComponentAuthorizable reportingTask = lookup.getReportingTask(id);
|
||||||
reportingTask.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
reportingTask.getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||||
|
|
||||||
|
// verify any referenced services
|
||||||
|
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(reportingTask, authorizer, lookup, false);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyDeleteReportingTask(id),
|
() -> serviceFacade.verifyDeleteReportingTask(id),
|
||||||
(revision, reportingTaskEntity) -> {
|
(revision, reportingTaskEntity) -> {
|
||||||
|
|
|
@ -23,8 +23,10 @@ import com.wordnik.swagger.annotations.ApiResponse;
|
||||||
import com.wordnik.swagger.annotations.ApiResponses;
|
import com.wordnik.swagger.annotations.ApiResponses;
|
||||||
import com.wordnik.swagger.annotations.Authorization;
|
import com.wordnik.swagger.annotations.Authorization;
|
||||||
import org.apache.nifi.authorization.AccessDeniedException;
|
import org.apache.nifi.authorization.AccessDeniedException;
|
||||||
|
import org.apache.nifi.authorization.AuthorizableLookup;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
import org.apache.nifi.authorization.RequestAction;
|
import org.apache.nifi.authorization.RequestAction;
|
||||||
|
import org.apache.nifi.authorization.resource.Authorizable;
|
||||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||||
import org.apache.nifi.controller.Snippet;
|
import org.apache.nifi.controller.Snippet;
|
||||||
import org.apache.nifi.web.NiFiServiceFacade;
|
import org.apache.nifi.web.NiFiServiceFacade;
|
||||||
|
@ -47,6 +49,7 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,6 +94,32 @@ public class SnippetResource extends ApplicationResource {
|
||||||
// snippets
|
// snippets
|
||||||
// --------
|
// --------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorizes the specified snippet request with the specified request action. This method is used when creating a snippet. Because we do not know what
|
||||||
|
* the snippet will be used for, we just ensure the user has permissions to each selected component. Some actions may require additional permissions
|
||||||
|
* (including referenced services) but those will be enforced when the snippet is used.
|
||||||
|
*
|
||||||
|
* @param authorizer authorizer
|
||||||
|
* @param lookup lookup
|
||||||
|
* @param action action
|
||||||
|
*/
|
||||||
|
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());
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
snippetRequest.getRemoteProcessGroups().keySet().stream().map(id -> lookup.getRemoteProcessGroup(id)).forEach(authorize);
|
||||||
|
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.getFunnels().keySet().stream().map(id -> lookup.getFunnel(id)).forEach(authorize);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a snippet based off the specified configuration.
|
* Creates a snippet based off the specified configuration.
|
||||||
*
|
*
|
||||||
|
@ -102,7 +131,7 @@ public class SnippetResource extends ApplicationResource {
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Creates a snippet",
|
value = "Creates a snippet. The snippet will be automatically discarded if not used in a subsequent request after 1 minute.",
|
||||||
response = SnippetEntity.class,
|
response = SnippetEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Read or Write - /{component-type}/{uuid} - For every component (all Read or all Write) in the Snippet and their descendant components", type = "")
|
@Authorization(value = "Read or Write - /{component-type}/{uuid} - For every component (all Read or all Write) in the Snippet and their descendant components", type = "")
|
||||||
|
@ -141,7 +170,7 @@ public class SnippetResource extends ApplicationResource {
|
||||||
serviceFacade,
|
serviceFacade,
|
||||||
requestSnippetEntity,
|
requestSnippetEntity,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
final SnippetDTO snippet = requestSnippetEntity.getSnippet();
|
final SnippetDTO snippetRequest = requestSnippetEntity.getSnippet();
|
||||||
|
|
||||||
// the snippet being created may be used later for batch component modifications,
|
// the snippet being created may be used later for batch component modifications,
|
||||||
// copy/paste, or template creation. during those subsequent actions, the snippet
|
// copy/paste, or template creation. during those subsequent actions, the snippet
|
||||||
|
@ -150,9 +179,9 @@ public class SnippetResource extends ApplicationResource {
|
||||||
// read OR write
|
// read OR write
|
||||||
|
|
||||||
try {
|
try {
|
||||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.READ);
|
authorizeSnippetRequest(snippetRequest, authorizer, lookup, RequestAction.READ);
|
||||||
} catch (final AccessDeniedException e) {
|
} catch (final AccessDeniedException e) {
|
||||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE);
|
authorizeSnippetRequest(snippetRequest, authorizer, lookup, RequestAction.WRITE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
|
@ -183,7 +212,7 @@ public class SnippetResource extends ApplicationResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Move's the components in this Snippet into a new Process Group and drops the snippet",
|
value = "Move's the components in this Snippet into a new Process Group and discards the snippet",
|
||||||
response = SnippetEntity.class,
|
response = SnippetEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write Process Group - /process-groups/{uuid}", type = ""),
|
@Authorization(value = "Write Process Group - /process-groups/{uuid}", type = ""),
|
||||||
|
@ -238,9 +267,9 @@ public class SnippetResource extends ApplicationResource {
|
||||||
lookup.getProcessGroup(requestSnippetDTO.getParentGroupId()).getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
lookup.getProcessGroup(requestSnippetDTO.getParentGroupId()).getAuthorizable().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure write permission to every component in the snippet
|
// ensure write permission to every component in the snippet excluding referenced services
|
||||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE);
|
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE, false, false);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyUpdateSnippet(requestSnippetDTO, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
() -> serviceFacade.verifyUpdateSnippet(requestSnippetDTO, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
||||||
(revisions, snippetEntity) -> {
|
(revisions, snippetEntity) -> {
|
||||||
|
@ -264,7 +293,7 @@ public class SnippetResource extends ApplicationResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Deletes the components in a snippet and drops the snippet",
|
value = "Deletes the components in a snippet and discards the snippet",
|
||||||
response = SnippetEntity.class,
|
response = SnippetEntity.class,
|
||||||
authorizations = {
|
authorizations = {
|
||||||
@Authorization(value = "Write - /{component-type}/{uuid} - For each component in the Snippet and their descendant components", type = "")
|
@Authorization(value = "Write - /{component-type}/{uuid} - For each component in the Snippet and their descendant components", type = "")
|
||||||
|
@ -301,9 +330,9 @@ public class SnippetResource extends ApplicationResource {
|
||||||
requestEntity,
|
requestEntity,
|
||||||
requestRevisions,
|
requestRevisions,
|
||||||
lookup -> {
|
lookup -> {
|
||||||
// ensure read permission to every component in the snippet
|
// ensure write permission to every component in the snippet excluding referenced services
|
||||||
final Snippet snippet = lookup.getSnippet(snippetId);
|
final Snippet snippet = lookup.getSnippet(snippetId);
|
||||||
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE);
|
authorizeSnippet(snippet, authorizer, lookup, RequestAction.WRITE, true, false);
|
||||||
},
|
},
|
||||||
() -> serviceFacade.verifyDeleteSnippet(snippetId, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
() -> serviceFacade.verifyDeleteSnippet(snippetId, requestRevisions.stream().map(rev -> rev.getComponentId()).collect(Collectors.toSet())),
|
||||||
(revisions, entity) -> {
|
(revisions, entity) -> {
|
||||||
|
|
Loading…
Reference in New Issue