use of org.apache.nifi.authorization.Authorizer in project nifi by apache.
the class FlowResource method scheduleComponents.
/**
* Updates the specified process group.
*
* @param httpServletRequest request
* @param id The id of the process group.
* @param requestScheduleComponentsEntity A scheduleComponentsEntity.
* @return A processGroupEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("process-groups/{id}")
@ApiOperation(value = "Schedule or unschedule components in the specified Process Group.", response = ScheduleComponentsEntity.class, authorizations = { @Authorization(value = "Read - /flow"), @Authorization(value = "Write - /{component-type}/{uuid} - For every component being scheduled/unscheduled") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response scheduleComponents(@Context HttpServletRequest httpServletRequest, @ApiParam(value = "The process group id.", required = true) @PathParam("id") String id, @ApiParam(value = "The request to schedule or unschedule. If the comopnents in the request are not specified, all authorized components will be considered.", required = true) final ScheduleComponentsEntity requestScheduleComponentsEntity) {
// ensure the same id is being used
if (!id.equals(requestScheduleComponentsEntity.getId())) {
throw new IllegalArgumentException(String.format("The process group id (%s) in the request body does " + "not equal the process group id of the requested resource (%s).", requestScheduleComponentsEntity.getId(), id));
}
final ScheduledState state;
if (requestScheduleComponentsEntity.getState() == null) {
throw new IllegalArgumentException("The scheduled state must be specified.");
} else {
try {
state = ScheduledState.valueOf(requestScheduleComponentsEntity.getState());
} catch (final IllegalArgumentException iae) {
throw new IllegalArgumentException(String.format("The scheduled must be one of [%s].", StringUtils.join(EnumSet.of(ScheduledState.RUNNING, ScheduledState.STOPPED), ", ")));
}
}
// ensure its a supported scheduled state
if (ScheduledState.DISABLED.equals(state) || ScheduledState.STARTING.equals(state) || ScheduledState.STOPPING.equals(state)) {
throw new IllegalArgumentException(String.format("The scheduled must be one of [%s].", StringUtils.join(EnumSet.of(ScheduledState.RUNNING, ScheduledState.STOPPED), ", ")));
}
// if the components are not specified, gather all components and their current revision
if (requestScheduleComponentsEntity.getComponents() == null) {
// get the current revisions for the components being updated
final Set<Revision> revisions = serviceFacade.getRevisionsFromGroup(id, group -> {
final Set<String> componentIds = new HashSet<>();
// ensure authorized for each processor we will attempt to schedule
group.findAllProcessors().stream().filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PROCESSORS : ProcessGroup.UNSCHEDULABLE_PROCESSORS).filter(processor -> processor.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser())).forEach(processor -> {
componentIds.add(processor.getIdentifier());
});
// ensure authorized for each input port we will attempt to schedule
group.findAllInputPorts().stream().filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS).filter(inputPort -> inputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser())).forEach(inputPort -> {
componentIds.add(inputPort.getIdentifier());
});
// ensure authorized for each output port we will attempt to schedule
group.findAllOutputPorts().stream().filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS).filter(outputPort -> outputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser())).forEach(outputPort -> {
componentIds.add(outputPort.getIdentifier());
});
return componentIds;
});
// build the component mapping
final Map<String, RevisionDTO> componentsToSchedule = new HashMap<>();
revisions.forEach(revision -> {
final RevisionDTO dto = new RevisionDTO();
dto.setClientId(revision.getClientId());
dto.setVersion(revision.getVersion());
componentsToSchedule.put(revision.getComponentId(), dto);
});
// set the components and their current revision
requestScheduleComponentsEntity.setComponents(componentsToSchedule);
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, requestScheduleComponentsEntity);
}
final Map<String, RevisionDTO> requestComponentsToSchedule = requestScheduleComponentsEntity.getComponents();
final Map<String, Revision> requestComponentRevisions = requestComponentsToSchedule.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getRevision(e.getValue(), e.getKey())));
final Set<Revision> requestRevisions = new HashSet<>(requestComponentRevisions.values());
return withWriteLock(serviceFacade, requestScheduleComponentsEntity, requestRevisions, lookup -> {
// ensure access to the flow
authorizeFlow();
// ensure access to every component being scheduled
requestComponentsToSchedule.keySet().forEach(componentId -> {
final Authorizable connectable = lookup.getLocalConnectable(componentId);
connectable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
});
}, () -> serviceFacade.verifyScheduleComponents(id, state, requestComponentRevisions.keySet()), (revisions, scheduleComponentsEntity) -> {
final ScheduledState scheduledState = ScheduledState.valueOf(scheduleComponentsEntity.getState());
final Map<String, RevisionDTO> componentsToSchedule = scheduleComponentsEntity.getComponents();
final Map<String, Revision> componentRevisions = componentsToSchedule.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getRevision(e.getValue(), e.getKey())));
// update the process group
final ScheduleComponentsEntity entity = serviceFacade.scheduleComponents(id, scheduledState, componentRevisions);
return generateOkResponse(entity).build();
});
}
use of org.apache.nifi.authorization.Authorizer in project nifi by apache.
the class ProcessGroupResource method copySnippet.
// ----------------
// snippet instance
// ----------------
/**
* Copies the specified snippet within this ProcessGroup. The snippet instance that is instantiated cannot be referenced at a later time, therefore there is no
* corresponding URI. Instead the request URI is returned.
* <p>
* Alternatively, we could have performed a PUT request. However, PUT requests are supposed to be idempotent and this endpoint is certainly not.
*
* @param httpServletRequest request
* @param groupId The group id
* @param requestCopySnippetEntity The copy snippet request
* @return A flowSnippetEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}/snippet-instance")
@ApiOperation(value = "Copies a snippet and discards it.", response = FlowEntity.class, authorizations = { @Authorization(value = "Write - /process-groups/{uuid}"), @Authorization(value = "Read - /{component-type}/{uuid} - For each component in the snippet and their descendant components"), @Authorization(value = "Write - if the snippet contains any restricted Processors - /restricted-components") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response copySnippet(@Context HttpServletRequest httpServletRequest, @ApiParam(value = "The process group id.", required = true) @PathParam("id") String groupId, @ApiParam(value = "The copy snippet request.", required = true) CopySnippetRequestEntity requestCopySnippetEntity) {
// ensure the position has been specified
if (requestCopySnippetEntity == null || requestCopySnippetEntity.getOriginX() == null || requestCopySnippetEntity.getOriginY() == null) {
throw new IllegalArgumentException("The origin position (x, y) must be specified");
}
if (requestCopySnippetEntity.getSnippetId() == null) {
throw new IllegalArgumentException("The snippet id must be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, requestCopySnippetEntity);
}
return withWriteLock(serviceFacade, requestCopySnippetEntity, lookup -> {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final SnippetAuthorizable snippet = authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), false);
final Consumer<ComponentAuthorizable> authorizeRestricted = authorizable -> {
if (authorizable.isRestricted()) {
authorizeRestrictions(authorizer, authorizable);
}
};
// 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 -> {
// copy the specified snippet
final FlowEntity flowEntity = serviceFacade.copySnippet(groupId, copySnippetRequestEntity.getSnippetId(), copySnippetRequestEntity.getOriginX(), copySnippetRequestEntity.getOriginY(), getIdGenerationSeed().orElse(null));
// get the snippet
final FlowDTO flow = flowEntity.getFlow();
// prune response as necessary
for (ProcessGroupEntity childGroupEntity : flow.getProcessGroups()) {
childGroupEntity.getComponent().setContents(null);
}
// create the response entity
populateRemainingSnippetContent(flow);
// generate the response
return generateCreatedResponse(getAbsolutePath(), flowEntity).build();
});
}
use of org.apache.nifi.authorization.Authorizer in project nifi by apache.
the class ProcessGroupResource method submitUpdateVariableRegistryRequest.
/**
* Updates the variable registry for the specified process group.
*
* @param httpServletRequest request
* @param groupId The id of the process group.
* @param requestVariableRegistryEntity the Variable Registry Entity
* @return A Variable Registry Entry.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}/variable-registry/update-requests")
@ApiOperation(value = "Submits a request to update a process group's variable registry", response = VariableRegistryUpdateRequestEntity.class, notes = NON_GUARANTEED_ENDPOINT, authorizations = { @Authorization(value = "Write - /process-groups/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response submitUpdateVariableRegistryRequest(@Context final HttpServletRequest httpServletRequest, @ApiParam(value = "The process group id.", required = true) @PathParam("id") final String groupId, @ApiParam(value = "The variable registry configuration details.", required = true) final VariableRegistryEntity requestVariableRegistryEntity) {
if (requestVariableRegistryEntity == null || requestVariableRegistryEntity.getVariableRegistry() == null) {
throw new IllegalArgumentException("Variable Registry details must be specified.");
}
if (requestVariableRegistryEntity.getProcessGroupRevision() == null) {
throw new IllegalArgumentException("Process Group Revision must be specified.");
}
// In order to update variables in a variable registry, we have to perform the following steps:
// 1. Determine Affected Components (this includes any Processors and Controller Services and any components that reference an affected Controller Service).
// 1a. Determine ID's of components
// 1b. Determine Revision's of associated components
// 2. Stop All Active Affected Processors
// 3. Disable All Active Affected Controller Services
// 4. Update the Variables
// 5. Re-Enable all previously Active Affected Controller Services (services only, not dependent components)
// 6. Re-Enable all previously Active Processors that Depended on the Controller Services
// Determine the affected components (and their associated revisions)
final VariableRegistryEntity computedEntity = serviceFacade.populateAffectedComponents(requestVariableRegistryEntity.getVariableRegistry());
final VariableRegistryDTO computedRegistryDto = computedEntity.getVariableRegistry();
if (computedRegistryDto == null) {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
final Set<AffectedComponentEntity> allAffectedComponents = serviceFacade.getComponentsAffectedByVariableRegistryUpdate(requestVariableRegistryEntity.getVariableRegistry());
final Set<AffectedComponentDTO> activeAffectedComponents = serviceFacade.getActiveComponentsAffectedByVariableRegistryUpdate(requestVariableRegistryEntity.getVariableRegistry());
final Map<String, List<AffectedComponentDTO>> activeAffectedComponentsByType = activeAffectedComponents.stream().collect(Collectors.groupingBy(comp -> comp.getReferenceType()));
final List<AffectedComponentDTO> activeAffectedProcessors = activeAffectedComponentsByType.get(AffectedComponentDTO.COMPONENT_TYPE_PROCESSOR);
final List<AffectedComponentDTO> activeAffectedServices = activeAffectedComponentsByType.get(AffectedComponentDTO.COMPONENT_TYPE_CONTROLLER_SERVICE);
final NiFiUser user = NiFiUserUtils.getNiFiUser();
// define access authorize for execution below
final AuthorizeAccess authorizeAccess = lookup -> {
final Authorizable groupAuthorizable = lookup.getProcessGroup(groupId).getAuthorizable();
groupAuthorizable.authorize(authorizer, RequestAction.WRITE, user);
// (because this action requires stopping the component).
if (activeAffectedProcessors != null) {
for (final AffectedComponentDTO activeAffectedComponent : activeAffectedProcessors) {
final Authorizable authorizable = lookup.getProcessor(activeAffectedComponent.getId()).getAuthorizable();
authorizable.authorize(authorizer, RequestAction.READ, user);
authorizable.authorize(authorizer, RequestAction.WRITE, user);
}
}
if (activeAffectedServices != null) {
for (final AffectedComponentDTO activeAffectedComponent : activeAffectedServices) {
final Authorizable authorizable = lookup.getControllerService(activeAffectedComponent.getId()).getAuthorizable();
authorizable.authorize(authorizer, RequestAction.READ, user);
authorizable.authorize(authorizer, RequestAction.WRITE, user);
}
}
};
if (isReplicateRequest()) {
// authorize access
serviceFacade.authorizeAccess(authorizeAccess);
// update the variable registry
final VariableRegistryUpdateRequest updateRequest = createVariableRegistryUpdateRequest(groupId, allAffectedComponents, user);
updateRequest.getIdentifyRelevantComponentsStep().setComplete(true);
final URI originalUri = getAbsolutePath();
// Submit the task to be run in the background
final Runnable taskWrapper = () -> {
try {
// set the user authentication token
final Authentication authentication = new NiFiAuthenticationToken(new NiFiUserDetails(user));
SecurityContextHolder.getContext().setAuthentication(authentication);
updateVariableRegistryReplicated(groupId, originalUri, activeAffectedProcessors, activeAffectedServices, updateRequest, requestVariableRegistryEntity);
// ensure the request is marked complete
updateRequest.setComplete(true);
} catch (final Exception e) {
logger.error("Failed to update variable registry", e);
updateRequest.setComplete(true);
updateRequest.setFailureReason("An unexpected error has occurred: " + e);
} finally {
// clear the authentication token
SecurityContextHolder.getContext().setAuthentication(null);
}
};
variableRegistryThreadPool.submit(taskWrapper);
final VariableRegistryUpdateRequestEntity responseEntity = new VariableRegistryUpdateRequestEntity();
responseEntity.setRequest(dtoFactory.createVariableRegistryUpdateRequestDto(updateRequest));
responseEntity.setProcessGroupRevision(updateRequest.getProcessGroupRevision());
responseEntity.getRequest().setUri(generateResourceUri("process-groups", groupId, "variable-registry", "update-requests", updateRequest.getRequestId()));
final URI location = URI.create(responseEntity.getRequest().getUri());
return Response.status(Status.ACCEPTED).location(location).entity(responseEntity).build();
}
final UpdateVariableRegistryRequestWrapper requestWrapper = new UpdateVariableRegistryRequestWrapper(allAffectedComponents, activeAffectedProcessors, activeAffectedServices, requestVariableRegistryEntity);
final Revision requestRevision = getRevision(requestVariableRegistryEntity.getProcessGroupRevision(), groupId);
return withWriteLock(serviceFacade, requestWrapper, requestRevision, authorizeAccess, null, (revision, wrapper) -> updateVariableRegistryLocal(groupId, wrapper.getAllAffectedComponents(), wrapper.getActiveAffectedProcessors(), wrapper.getActiveAffectedServices(), user, revision, wrapper.getVariableRegistryEntity()));
}
use of org.apache.nifi.authorization.Authorizer in project nifi by apache.
the class StandardNiFiServiceFacadeTest method setUp.
@Before
public void setUp() throws Exception {
// audit service
final AuditService auditService = mock(AuditService.class);
when(auditService.getAction(anyInt())).then(invocation -> {
final Integer actionId = invocation.getArgumentAt(0, Integer.class);
FlowChangeAction action = null;
if (ACTION_ID_1.equals(actionId)) {
action = getAction(actionId, PROCESSOR_ID_1);
} else if (ACTION_ID_2.equals(actionId)) {
action = getAction(actionId, PROCESSOR_ID_2);
}
return action;
});
when(auditService.getActions(any(HistoryQuery.class))).then(invocation -> {
final History history = new History();
history.setActions(Arrays.asList(getAction(ACTION_ID_1, PROCESSOR_ID_1), getAction(ACTION_ID_2, PROCESSOR_ID_2)));
return history;
});
// authorizable lookup
final AuthorizableLookup authorizableLookup = mock(AuthorizableLookup.class);
when(authorizableLookup.getProcessor(Mockito.anyString())).then(getProcessorInvocation -> {
final String processorId = getProcessorInvocation.getArgumentAt(0, String.class);
// processor-2 is no longer part of the flow
if (processorId.equals(PROCESSOR_ID_2)) {
throw new ResourceNotFoundException("");
}
// component authorizable
final ComponentAuthorizable componentAuthorizable = mock(ComponentAuthorizable.class);
when(componentAuthorizable.getAuthorizable()).then(getAuthorizableInvocation -> {
// authorizable
final Authorizable authorizable = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getComponentResource(ResourceType.Processor, processorId, processorId);
}
};
return authorizable;
});
return componentAuthorizable;
});
// authorizer
authorizer = mock(Authorizer.class);
when(authorizer.authorize(any(AuthorizationRequest.class))).then(invocation -> {
final AuthorizationRequest request = invocation.getArgumentAt(0, AuthorizationRequest.class);
AuthorizationResult result = AuthorizationResult.denied();
if (request.getResource().getIdentifier().endsWith(PROCESSOR_ID_1)) {
if (USER_1.equals(request.getIdentity())) {
result = AuthorizationResult.approved();
}
} else if (request.getResource().equals(ResourceFactory.getControllerResource())) {
if (USER_2.equals(request.getIdentity())) {
result = AuthorizationResult.approved();
}
}
return result;
});
// flow controller
final FlowController controller = mock(FlowController.class);
when(controller.getResource()).thenCallRealMethod();
when(controller.getParentAuthorizable()).thenCallRealMethod();
// controller facade
final ControllerFacade controllerFacade = new ControllerFacade();
controllerFacade.setFlowController(controller);
serviceFacade = new StandardNiFiServiceFacade();
serviceFacade.setAuditService(auditService);
serviceFacade.setAuthorizableLookup(authorizableLookup);
serviceFacade.setAuthorizer(authorizer);
serviceFacade.setEntityFactory(new EntityFactory());
serviceFacade.setDtoFactory(new DtoFactory());
serviceFacade.setControllerFacade(controllerFacade);
}
use of org.apache.nifi.authorization.Authorizer in project nifi by apache.
the class X509AuthenticationProviderTest method setup.
@Before
public void setup() {
extractor = new SubjectDnX509PrincipalExtractor();
certificateIdentityProvider = mock(X509IdentityProvider.class);
when(certificateIdentityProvider.authenticate(any(X509Certificate[].class))).then(invocation -> {
final X509Certificate[] certChain = invocation.getArgumentAt(0, X509Certificate[].class);
final String identity = extractor.extractPrincipal(certChain[0]).toString();
if (INVALID_CERTIFICATE.equals(identity)) {
throw new IllegalArgumentException();
}
return new AuthenticationResponse(identity, identity, TimeUnit.MILLISECONDS.convert(12, TimeUnit.HOURS), "");
});
authorizer = mock(Authorizer.class);
when(authorizer.authorize(any(AuthorizationRequest.class))).then(invocation -> {
final AuthorizationRequest request = invocation.getArgumentAt(0, AuthorizationRequest.class);
if (UNTRUSTED_PROXY.equals(request.getIdentity())) {
return AuthorizationResult.denied();
}
return AuthorizationResult.approved();
});
x509AuthenticationProvider = new X509AuthenticationProvider(certificateIdentityProvider, authorizer, NiFiProperties.createBasicNiFiProperties(null, null));
}
Aggregations