NIFI-4885:

- Updating the versioning endpoints to account for the granular access restrictions.

This closes #2573.

Signed-off-by: Bryan Bende <bbende@apache.org>
This commit is contained in:
Matt Gilman 2018-03-21 10:23:49 -04:00 committed by Bryan Bende
parent 478e34082d
commit 98cd9ad531
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
5 changed files with 63 additions and 42 deletions

View File

@ -17,6 +17,7 @@
package org.apache.nifi.authorization; package org.apache.nifi.authorization;
import org.apache.nifi.authorization.resource.Authorizable; import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.RequiredPermission; import org.apache.nifi.components.RequiredPermission;
import org.apache.nifi.web.api.dto.BundleDTO; import org.apache.nifi.web.api.dto.BundleDTO;
import org.apache.nifi.web.api.dto.FlowSnippetDTO; import org.apache.nifi.web.api.dto.FlowSnippetDTO;
@ -41,6 +42,15 @@ public interface AuthorizableLookup {
*/ */
ComponentAuthorizable getConfigurableComponent(String type, BundleDTO bundle); ComponentAuthorizable getConfigurableComponent(String type, BundleDTO bundle);
/**
* Get the authorizable for the given ConfigurableComponent. This will use a dummy instance of
* the component.
*
* @param configurableComponent the configurable component
* @return authorizable
*/
ComponentAuthorizable getConfigurableComponent(ConfigurableComponent configurableComponent);
/** /**
* Get the authorizable Processor. * Get the authorizable Processor.
* *

View File

@ -181,8 +181,13 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
@Override @Override
public ComponentAuthorizable getConfigurableComponent(final String type, final BundleDTO bundle) { public ComponentAuthorizable getConfigurableComponent(final String type, final BundleDTO bundle) {
try {
final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(type, bundle); final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(type, bundle);
return getConfigurableComponent(configurableComponent);
}
@Override
public ComponentAuthorizable getConfigurableComponent(ConfigurableComponent configurableComponent) {
try {
return new ConfigurableComponentAuthorizable(configurableComponent); return new ConfigurableComponentAuthorizable(configurableComponent);
} catch (final Exception e) { } catch (final Exception e) {
throw new AccessDeniedException("Unable to create component to verify if it references any Controller Services."); throw new AccessDeniedException("Unable to create component to verify if it references any Controller Services.");

View File

@ -17,9 +17,6 @@
package org.apache.nifi.registry.flow; package org.apache.nifi.registry.flow;
import java.util.HashSet;
import java.util.Set;
import org.apache.nifi.annotation.behavior.Restricted; import org.apache.nifi.annotation.behavior.Restricted;
import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.ConfigurableComponent; import org.apache.nifi.components.ConfigurableComponent;
@ -28,9 +25,14 @@ import org.apache.nifi.util.Tuple;
import org.apache.nifi.web.NiFiCoreException; import org.apache.nifi.web.NiFiCoreException;
import org.apache.nifi.web.api.dto.BundleDTO; import org.apache.nifi.web.api.dto.BundleDTO;
import java.util.HashSet;
import java.util.Set;
public class FlowRegistryUtils { public class FlowRegistryUtils {
public static boolean containsRestrictedComponent(final VersionedProcessGroup group) { public static Set<ConfigurableComponent> getRestrictedComponents(final VersionedProcessGroup group) {
final Set<ConfigurableComponent> restrictedComponents = new HashSet<>();
final Set<Tuple<String, BundleCoordinate>> componentTypes = new HashSet<>(); final Set<Tuple<String, BundleCoordinate>> componentTypes = new HashSet<>();
populateComponentTypes(group, componentTypes); populateComponentTypes(group, componentTypes);
@ -42,11 +44,11 @@ public class FlowRegistryUtils {
final boolean isRestricted = component.getClass().isAnnotationPresent(Restricted.class); final boolean isRestricted = component.getClass().isAnnotationPresent(Restricted.class);
if (isRestricted) { if (isRestricted) {
return true; restrictedComponents.add(component);
} }
} }
return false; return restrictedComponents;
} }
private static void populateComponentTypes(final VersionedProcessGroup group, final Set<Tuple<String, BundleCoordinate>> componentTypes) { private static void populateComponentTypes(final VersionedProcessGroup group, final Set<Tuple<String, BundleCoordinate>> componentTypes) {

View File

@ -40,6 +40,7 @@ import org.apache.nifi.authorization.user.NiFiUserDetails;
import org.apache.nifi.authorization.user.NiFiUserUtils; import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.cluster.manager.NodeResponse; import org.apache.nifi.cluster.manager.NodeResponse;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.connectable.ConnectableType; import org.apache.nifi.connectable.ConnectableType;
import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.serialization.FlowEncodingVersion; import org.apache.nifi.controller.serialization.FlowEncodingVersion;
@ -1689,10 +1690,11 @@ public class ProcessGroupResource extends ApplicationResource {
// for write access to the RestrictedComponents resource // for write access to the RestrictedComponents resource
final VersionedFlowSnapshot versionedFlowSnapshot = requestProcessGroupEntity.getVersionedFlowSnapshot(); final VersionedFlowSnapshot versionedFlowSnapshot = requestProcessGroupEntity.getVersionedFlowSnapshot();
if (versionedFlowSnapshot != null) { if (versionedFlowSnapshot != null) {
final boolean containsRestrictedComponent = FlowRegistryUtils.containsRestrictedComponent(versionedFlowSnapshot.getFlowContents()); final Set<ConfigurableComponent> restrictedComponents = FlowRegistryUtils.getRestrictedComponents(versionedFlowSnapshot.getFlowContents());
if (containsRestrictedComponent) { restrictedComponents.forEach(restrictedComponent -> {
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); final ComponentAuthorizable restrictedComponentAuthorizable = lookup.getConfigurableComponent(restrictedComponent);
} authorizeRestrictions(authorizer, restrictedComponentAuthorizable);
});
} }
}, },
() -> { () -> {

View File

@ -17,31 +17,23 @@
package org.apache.nifi.web.api; package org.apache.nifi.web.api;
import javax.ws.rs.Consumes; import io.swagger.annotations.Api;
import javax.ws.rs.DELETE; import io.swagger.annotations.ApiOperation;
import javax.ws.rs.DefaultValue; import io.swagger.annotations.ApiParam;
import javax.ws.rs.GET; import io.swagger.annotations.ApiResponse;
import javax.ws.rs.HttpMethod; import io.swagger.annotations.ApiResponses;
import javax.ws.rs.POST; import io.swagger.annotations.Authorization;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.AccessDeniedException; import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.ComponentAuthorizable;
import org.apache.nifi.authorization.ProcessGroupAuthorizable; 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;
import org.apache.nifi.authorization.user.NiFiUserUtils; import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.manager.NodeResponse; import org.apache.nifi.cluster.manager.NodeResponse;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.service.ControllerServiceState; import org.apache.nifi.controller.service.ControllerServiceState;
@ -85,6 +77,21 @@ import org.apache.nifi.web.util.LifecycleManagementException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -100,13 +107,6 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
@Path("/versions") @Path("/versions")
@Api(value = "/versions", description = "Endpoint for managing version control for a flow") @Api(value = "/versions", description = "Endpoint for managing version control for a flow")
public class VersionsResource extends ApplicationResource { public class VersionsResource extends ApplicationResource {
@ -1113,10 +1113,11 @@ public class VersionsResource extends ApplicationResource {
authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.WRITE, true, false, true, true); authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.WRITE, true, false, true, true);
final VersionedProcessGroup groupContents = flowSnapshot.getFlowContents(); final VersionedProcessGroup groupContents = flowSnapshot.getFlowContents();
final boolean containsRestrictedComponents = FlowRegistryUtils.containsRestrictedComponent(groupContents); final Set<ConfigurableComponent> restrictedComponents = FlowRegistryUtils.getRestrictedComponents(groupContents);
if (containsRestrictedComponents) { restrictedComponents.forEach(restrictedComponent -> {
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); final ComponentAuthorizable restrictedComponentAuthorizable = lookup.getConfigurableComponent(restrictedComponent);
} authorizeRestrictions(authorizer, restrictedComponentAuthorizable);
});
}, },
() -> { () -> {
// Step 3: Verify that all components in the snapshot exist on all nodes // Step 3: Verify that all components in the snapshot exist on all nodes
@ -1269,10 +1270,11 @@ public class VersionsResource extends ApplicationResource {
authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.WRITE, true, false, true, true); authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.WRITE, true, false, true, true);
final VersionedProcessGroup groupContents = flowSnapshot.getFlowContents(); final VersionedProcessGroup groupContents = flowSnapshot.getFlowContents();
final boolean containsRestrictedComponents = FlowRegistryUtils.containsRestrictedComponent(groupContents); final Set<ConfigurableComponent> restrictedComponents = FlowRegistryUtils.getRestrictedComponents(groupContents);
if (containsRestrictedComponents) { restrictedComponents.forEach(restrictedComponent -> {
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); final ComponentAuthorizable restrictedComponentAuthorizable = lookup.getConfigurableComponent(restrictedComponent);
} authorizeRestrictions(authorizer, restrictedComponentAuthorizable);
});
}, },
() -> { () -> {
// Step 3: Verify that all components in the snapshot exist on all nodes // Step 3: Verify that all components in the snapshot exist on all nodes