Пример #1
0
  /**
   * Retrieves the specified access policy.
   *
   * @return An accessPolicyEntity.
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{action}/{resource: .+}")
  // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
  @ApiOperation(
      value = "Gets an access policy",
      response = AccessPolicyEntity.class,
      authorizations = {
        @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
        @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
        @Authorization(value = "Administrator", type = "ROLE_ADMIN")
      })
  @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 getAccessPolicyForResource(
      @ApiParam(value = "The request action.", allowableValues = "read, write", required = true)
          @PathParam("action")
          final String action,
      @ApiParam(value = "The resource of the policy.", required = true) @PathParam("resource")
          String rawResource) {

    // parse the action and resource type
    final RequestAction requestAction = RequestAction.valueOfValue(action);
    final String resource = "/" + rawResource;

    if (isReplicateRequest()) {
      return replicate(HttpMethod.GET);
    }

    // authorize access
    serviceFacade.authorizeAccess(
        lookup -> {
          final Authorizable accessPolicy = lookup.getAccessPolicyByResource(resource);
          accessPolicy.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
        });

    // get the access policy
    final AccessPolicyEntity entity = serviceFacade.getAccessPolicy(requestAction, resource);
    populateRemainingAccessPolicyEntityContent(entity);

    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #2
0
 /**
  * Executes an action through the service facade using the specified revision.
  *
  * @param serviceFacade service facade
  * @param revisions revisions
  * @param authorizer authorizer
  * @param verifier verifier
  * @param action executor
  * @return the response
  */
 protected Response withWriteLock(
     final NiFiServiceFacade serviceFacade,
     final Set<Revision> revisions,
     final AuthorizeAccess authorizer,
     final Runnable verifier,
     final Supplier<Response> action) {
   final NiFiUser user = NiFiUserUtils.getNiFiUser();
   return withWriteLock(
       serviceFacade,
       authorizer,
       verifier,
       action,
       () -> serviceFacade.claimRevisions(revisions, user),
       () -> serviceFacade.cancelRevisions(revisions),
       () -> serviceFacade.releaseRevisionClaims(revisions, user));
 }
Пример #3
0
  /**
   * Gets the details for a provenance event.
   *
   * @param id The id of the event
   * @param clusterNodeId The id of node in the cluster that the event/flowfile originated from.
   *     This is only required when clustered.
   * @return A provenanceEventEntity
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_PROVENANCE')")
  @ApiOperation(
      value = "Gets a provenance event",
      response = ProvenanceEventEntity.class,
      authorizations = {@Authorization(value = "Provenance", type = "ROLE_PROVENANCE")})
  @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 getProvenanceEvent(
      @ApiParam(
              value = "The id of the node where this event exists if clustered.",
              required = false)
          @QueryParam("clusterNodeId")
          final String clusterNodeId,
      @ApiParam(value = "The provenence event id.", required = true) @PathParam("id")
          final LongParameter id) {

    // ensure the id is specified
    if (id == null) {
      throw new IllegalArgumentException("Provenance event id must be specified.");
    }

    // replicate if cluster manager
    if (isReplicateRequest()) {
      // since we're cluster we must specify the cluster node identifier
      if (clusterNodeId == null) {
        throw new IllegalArgumentException("The cluster node identifier must be specified.");
      }

      return replicate(HttpMethod.GET, clusterNodeId);
    }

    // get the provenance event
    final ProvenanceEventDTO event = serviceFacade.getProvenanceEvent(id.getLong());
    event.setClusterNodeId(clusterNodeId);

    // create a response entity
    final ProvenanceEventEntity entity = new ProvenanceEventEntity();
    entity.setProvenanceEvent(event);

    // generate the response
    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #4
0
  /**
   * Retrieves the specified input port.
   *
   * @param clientId Optional client id. If the client id is not specified, a new one will be
   *     generated. This value (whether specified or generated) is included in the response.
   * @param id The id of the input port to retrieve
   * @return A inputPortEntity.
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
  @ApiOperation(
      value = "Gets an input port",
      response = InputPortEntity.class,
      authorizations = {
        @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
        @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
        @Authorization(value = "Administrator", type = "ROLE_ADMIN")
      })
  @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 getInputPort(
      @ApiParam(
              value =
                  "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
              required = false)
          @QueryParam(CLIENT_ID)
          @DefaultValue(StringUtils.EMPTY)
          ClientIdParameter clientId,
      @ApiParam(value = "The input port id.", required = true) @PathParam("id") String id) {

    // replicate if cluster manager
    if (properties.isClusterManager()) {
      return clusterManager
          .applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders())
          .getResponse();
    }

    // get the port
    final PortDTO port = serviceFacade.getInputPort(id);

    // create the revision
    final RevisionDTO revision = new RevisionDTO();
    revision.setClientId(clientId.getClientId());

    // create the response entity
    final InputPortEntity entity = new InputPortEntity();
    entity.setRevision(revision);
    entity.setInputPort(populateRemainingInputPortContent(port));

    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #5
0
  /**
   * Retrieves the specified output port.
   *
   * @param id The id of the output port to retrieve
   * @return A outputPortEntity.
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  @ApiOperation(
      value = "Gets an output port",
      response = PortEntity.class,
      authorizations = {@Authorization(value = "Read - /output-ports/{uuid}", type = "")})
  @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 getOutputPort(
      @ApiParam(value = "The output port id.", required = true) @PathParam("id") final String id) {

    if (isReplicateRequest()) {
      return replicate(HttpMethod.GET);
    }

    // authorize access
    serviceFacade.authorizeAccess(
        lookup -> {
          final Authorizable outputPort = lookup.getOutputPort(id);
          outputPort.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
        });

    // get the port
    final PortEntity entity = serviceFacade.getOutputPort(id);
    populateRemainingOutputPortEntityContent(entity);

    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #6
0
  /**
   * Removes the specified template.
   *
   * @param httpServletRequest request
   * @param id The id of the template to remove.
   * @return A templateEntity.
   */
  @DELETE
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  @ApiOperation(
      value = "Deletes a template",
      response = TemplateEntity.class,
      authorizations = {@Authorization(value = "Write - /templates/{uuid}", type = "")})
  @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 removeTemplate(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The template id.", required = true) @PathParam("id") final String id) {

    if (isReplicateRequest()) {
      return replicate(HttpMethod.DELETE);
    }

    final TemplateEntity requestTemplateEntity = new TemplateEntity();
    requestTemplateEntity.setId(id);

    return withWriteLock(
        serviceFacade,
        requestTemplateEntity,
        lookup -> {
          final Authorizable template = lookup.getTemplate(id);
          template.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
        },
        null,
        (templateEntity) -> {
          // delete the specified template
          serviceFacade.deleteTemplate(templateEntity.getId());

          // build the response entity
          final TemplateEntity entity = new TemplateEntity();

          return clusterContext(generateOkResponse(entity)).build();
        });
  }
Пример #7
0
  /**
   * Returns the details of this NiFi.
   *
   * @return A controllerEntity.
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @ApiOperation(
      value = "Returns the details about this NiFi necessary to communicate via site to site",
      response = ControllerEntity.class,
      authorizations = {@Authorization(value = "Read - /site-to-site", type = "")})
  @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 = 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 getSiteToSiteDetails(@Context HttpServletRequest req) {

    authorizeSiteToSite();

    if (isReplicateRequest()) {
      return replicate(HttpMethod.GET);
    }

    // get the controller dto
    final ControllerDTO controller = serviceFacade.getSiteToSiteDetails();

    // build the response entity
    final ControllerEntity entity = new ControllerEntity();
    entity.setController(controller);

    if (isEmpty(req.getHeader(HttpHeaders.PROTOCOL_VERSION))) {
      // This indicates the client uses older NiFi version,
      // which strictly read JSON properties and fail with unknown properties.
      // Convert result entity so that old version clients can understand.
      logger.debug("Converting result to provide backward compatibility...");
      controller.setRemoteSiteHttpListeningPort(null);
    }

    // generate the response
    return clusterContext(noCache(Response.ok(entity))).build();
  }
Пример #8
0
  /**
   * Executes an action through the service facade using the specified revision.
   *
   * @param serviceFacade service facade
   * @param authorizer authorizer
   * @param verifier verifier
   * @param action the action to execute
   * @param claimRevision a callback that will claim the necessary revisions for the operation
   * @param cancelRevision a callback that will cancel the necessary revisions if the operation
   *     fails
   * @param releaseClaim a callback that will release any previously claimed revision if the
   *     operation is canceled after the first phase
   * @return the response
   */
  private Response withWriteLock(
      final NiFiServiceFacade serviceFacade,
      final AuthorizeAccess authorizer,
      final Runnable verifier,
      final Supplier<Response> action,
      final Runnable claimRevision,
      final Runnable cancelRevision,
      final Runnable releaseClaim) {

    if (isClaimCancelationPhase(httpServletRequest)) {
      releaseClaim.run();
      return generateOkResponse().build();
    }

    final boolean validationPhase = isValidationPhase(httpServletRequest);
    if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
      // authorize access
      serviceFacade.authorizeAccess(authorizer);
      claimRevision.run();
    }

    try {
      if (validationPhase) {
        if (verifier != null) {
          verifier.run();
        }
        return generateContinueResponse().build();
      }
    } catch (final Exception e) {
      cancelRevision.run();
      throw e;
    }

    try {
      return action.get();
    } finally {
      cancelRevision.run();
    }
  }
Пример #9
0
  /**
   * Gets the content for the input of the specified event.
   *
   * @param clusterNodeId The id of the node within the cluster this content is on. Required if
   *     clustered.
   * @param id The id of the provenance event associated with this content.
   * @return The content stream
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.WILDCARD)
  @Path("{id}/content/input")
  // TODO - @PreAuthorize("hasRole('ROLE_PROVENANCE')")
  @ApiOperation(
      value = "Gets the input content for a provenance event",
      authorizations = {@Authorization(value = "Provenance", type = "ROLE_PROVENANCE")})
  @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 getInputContent(
      @ApiParam(
              value = "The id of the node where the content exists if clustered.",
              required = false)
          @QueryParam("clusterNodeId")
          final String clusterNodeId,
      @ApiParam(value = "The provenance event id.", required = true) @PathParam("id")
          final LongParameter id) {

    // ensure proper input
    if (id == null) {
      throw new IllegalArgumentException("The event id must be specified.");
    }

    // replicate if cluster manager
    if (isReplicateRequest()) {
      // determine where this request should be sent
      if (clusterNodeId == null) {
        throw new IllegalArgumentException("The id of the node in the cluster is required.");
      } else {
        return replicate(HttpMethod.GET, clusterNodeId);
      }
    }

    // get the uri of the request
    final String uri =
        generateResourceUri(
            "provenance", "events", String.valueOf(id.getLong()), "content", "input");

    // get an input stream to the content
    final DownloadableContent content =
        serviceFacade.getContent(id.getLong(), uri, ContentDirection.INPUT);

    // generate a streaming response
    final StreamingOutput response =
        new StreamingOutput() {
          @Override
          public void write(OutputStream output) throws IOException, WebApplicationException {
            try (InputStream is = content.getContent()) {
              // stream the content to the response
              StreamUtils.copy(is, output);

              // flush the response
              output.flush();
            }
          }
        };

    // use the appropriate content type
    String contentType = content.getType();
    if (contentType == null) {
      contentType = MediaType.APPLICATION_OCTET_STREAM;
    }

    return generateOkResponse(response)
        .type(contentType)
        .header(
            "Content-Disposition",
            String.format("attachment; filename=\"%s\"", content.getFilename()))
        .build();
  }
Пример #10
0
  /**
   * Creates a new replay request for the content associated with the specified provenance event id.
   *
   * @param httpServletRequest request
   * @param replayRequestEntity The replay request
   * @return A provenanceEventEntity
   */
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("replays")
  // TODO - @PreAuthorize("hasRole('ROLE_PROVENANCE') and hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Replays content from a provenance event",
      response = ProvenanceEventEntity.class,
      authorizations = {
        @Authorization(
            value = "Provenance and Data Flow Manager",
            type = "ROLE_PROVENANCE and ROLE_DFM")
      })
  @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 submitReplay(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The replay request.", required = true)
          final SubmitReplayRequestEntity replayRequestEntity) {

    // ensure the event id is specified
    if (replayRequestEntity == null || replayRequestEntity.getEventId() == null) {
      throw new IllegalArgumentException("The id of the event must be specified.");
    }

    // replicate if cluster manager
    if (isReplicateRequest()) {
      // determine where this request should be sent
      if (replayRequestEntity.getClusterNodeId() == null) {
        throw new IllegalArgumentException("The id of the node in the cluster is required.");
      } else {
        return replicate(
            HttpMethod.POST, replayRequestEntity, replayRequestEntity.getClusterNodeId());
      }
    }

    // handle expects request (usually from the cluster manager)
    final String expects =
        httpServletRequest.getHeader(RequestReplicator.REQUEST_VALIDATION_HTTP_HEADER);
    if (expects != null) {
      return generateContinueResponse().build();
    }

    // submit the provenance replay request
    final ProvenanceEventDTO event = serviceFacade.submitReplay(replayRequestEntity.getEventId());

    // create a response entity
    final ProvenanceEventEntity entity = new ProvenanceEventEntity();
    entity.setProvenanceEvent(event);

    // generate the response
    URI uri = URI.create(generateResourceUri("provenance-events", event.getId()));
    return clusterContext(generateCreatedResponse(uri, entity)).build();
  }
Пример #11
0
  /**
   * Updates an access policy.
   *
   * @param httpServletRequest request
   * @param id The id of the access policy to update.
   * @param accessPolicyEntity An accessPolicyEntity.
   * @return An accessPolicyEntity.
   */
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Updates a access policy",
      response = AccessPolicyEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")})
  @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 updateAccessPolicy(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The access policy id.", required = true) @PathParam("id") final String id,
      @ApiParam(value = "The access policy configuration details.", required = true)
          final AccessPolicyEntity accessPolicyEntity) {

    if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
      throw new IllegalArgumentException("Access policy details must be specified.");
    }

    if (accessPolicyEntity.getRevision() == null) {
      throw new IllegalArgumentException("Revision must be specified.");
    }

    // ensure the ids are the same
    final AccessPolicyDTO accessPolicyDTO = accessPolicyEntity.getComponent();
    if (!id.equals(accessPolicyDTO.getId())) {
      throw new IllegalArgumentException(
          String.format(
              "The access policy id (%s) in the request body does not equal the "
                  + "access policy id of the requested resource (%s).",
              accessPolicyDTO.getId(), id));
    }

    if (isReplicateRequest()) {
      return replicate(HttpMethod.PUT, accessPolicyEntity);
    }

    // Extract the revision
    final Revision revision = getRevision(accessPolicyEntity, id);
    return withWriteLock(
        serviceFacade,
        revision,
        lookup -> {
          Authorizable authorizable = lookup.getAccessPolicyById(id);
          authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
        },
        null,
        () -> {
          // update the access policy
          final AccessPolicyEntity entity =
              serviceFacade.updateAccessPolicy(revision, accessPolicyDTO);
          populateRemainingAccessPolicyEntityContent(entity);

          return clusterContext(generateOkResponse(entity)).build();
        });
  }
Пример #12
0
  /**
   * Creates a new access policy.
   *
   * @param httpServletRequest request
   * @param accessPolicyEntity An accessPolicyEntity.
   * @return An accessPolicyEntity.
   */
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Creates an access policy",
      response = AccessPolicyEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")})
  @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 createAccessPolicy(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The access policy configuration details.", required = true)
          final AccessPolicyEntity accessPolicyEntity) {

    if (accessPolicyEntity == null || accessPolicyEntity.getComponent() == null) {
      throw new IllegalArgumentException("Access policy details must be specified.");
    }

    if (accessPolicyEntity.getRevision() == null
        || (accessPolicyEntity.getRevision().getVersion() == null
            || accessPolicyEntity.getRevision().getVersion() != 0)) {
      throw new IllegalArgumentException(
          "A revision of 0 must be specified when creating a new Policy.");
    }

    final AccessPolicyDTO requestAccessPolicy = accessPolicyEntity.getComponent();
    if (requestAccessPolicy.getId() != null) {
      throw new IllegalArgumentException("Access policy ID cannot be specified.");
    }

    if (requestAccessPolicy.getResource() == null) {
      throw new IllegalArgumentException("Access policy resource must be specified.");
    }

    // ensure this is a valid action
    RequestAction.valueOfValue(requestAccessPolicy.getAction());

    if (isReplicateRequest()) {
      return replicate(HttpMethod.POST, accessPolicyEntity);
    }

    // handle expects request (usually from the cluster manager)
    final boolean validationPhase = isValidationPhase(httpServletRequest);
    if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
      // authorize access
      serviceFacade.authorizeAccess(
          lookup -> {
            final Authorizable accessPolicies =
                lookup.getAccessPolicyByResource(requestAccessPolicy.getResource());
            accessPolicies.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
          });
    }
    if (validationPhase) {
      return generateContinueResponse().build();
    }

    // set the access policy id as appropriate
    requestAccessPolicy.setId(generateUuid());

    // get revision from the config
    final RevisionDTO revisionDTO = accessPolicyEntity.getRevision();
    Revision revision =
        new Revision(
            revisionDTO.getVersion(),
            revisionDTO.getClientId(),
            accessPolicyEntity.getComponent().getId());

    // create the access policy and generate the json
    final AccessPolicyEntity entity =
        serviceFacade.createAccessPolicy(revision, accessPolicyEntity.getComponent());
    populateRemainingAccessPolicyEntityContent(entity);

    // build the response
    return clusterContext(generateCreatedResponse(URI.create(entity.getUri()), entity)).build();
  }
Пример #13
0
  /**
   * Removes the specified input port.
   *
   * @param httpServletRequest request
   * @param version The revision is used to verify the client is working with the latest version of
   *     the flow.
   * @param clientId Optional client id. If the client id is not specified, a new one will be
   *     generated. This value (whether specified or generated) is included in the response.
   * @param id The id of the input port to remove.
   * @return A inputPortEntity.
   */
  @DELETE
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Deletes an input port",
      response = InputPortEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")})
  @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 removeInputPort(
      @Context HttpServletRequest httpServletRequest,
      @ApiParam(
              value =
                  "The revision is used to verify the client is working with the latest version of the flow.",
              required = false)
          @QueryParam(VERSION)
          LongParameter version,
      @ApiParam(
              value =
                  "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
              required = false)
          @QueryParam(CLIENT_ID)
          @DefaultValue(StringUtils.EMPTY)
          ClientIdParameter clientId,
      @ApiParam(value = "The input port id.", required = true) @PathParam("id") String id) {

    // replicate if cluster manager
    if (properties.isClusterManager()) {
      return clusterManager
          .applyRequest(
              HttpMethod.DELETE, getAbsolutePath(), getRequestParameters(true), getHeaders())
          .getResponse();
    }

    // handle expects request (usually from the cluster manager)
    final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
    if (expects != null) {
      serviceFacade.verifyDeleteInputPort(id);
      return generateContinueResponse().build();
    }

    // determine the specified version
    Long clientVersion = null;
    if (version != null) {
      clientVersion = version.getLong();
    }

    // delete the specified input port
    final ConfigurationSnapshot<Void> controllerResponse =
        serviceFacade.deleteInputPort(new Revision(clientVersion, clientId.getClientId()), id);

    // get the updated revision
    final RevisionDTO revision = new RevisionDTO();
    revision.setClientId(clientId.getClientId());
    revision.setVersion(controllerResponse.getVersion());

    // build the response entity
    final InputPortEntity entity = new InputPortEntity();
    entity.setRevision(revision);

    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #14
0
  /**
   * Updates the specified input port.
   *
   * @param httpServletRequest request
   * @param id The id of the input port to update.
   * @param portEntity A inputPortEntity.
   * @return A inputPortEntity.
   */
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Updates an input port",
      response = InputPortEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")})
  @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 updateInputPort(
      @Context HttpServletRequest httpServletRequest,
      @ApiParam(value = "The input port id.", required = true) @PathParam("id") String id,
      @ApiParam(value = "The input port configuration details.", required = true)
          InputPortEntity portEntity) {

    if (portEntity == null || portEntity.getInputPort() == null) {
      throw new IllegalArgumentException("Input port details must be specified.");
    }

    if (portEntity.getRevision() == null) {
      throw new IllegalArgumentException("Revision must be specified.");
    }

    // ensure the ids are the same
    final PortDTO requestPortDTO = portEntity.getInputPort();
    if (!id.equals(requestPortDTO.getId())) {
      throw new IllegalArgumentException(
          String.format(
              "The input port id (%s) in the request body does not equal the "
                  + "input port id of the requested resource (%s).",
              requestPortDTO.getId(), id));
    }

    // replicate if cluster manager
    if (properties.isClusterManager()) {
      // change content type to JSON for serializing entity
      final Map<String, String> headersToOverride = new HashMap<>();
      headersToOverride.put("content-type", MediaType.APPLICATION_JSON);

      // replicate the request
      return clusterManager
          .applyRequest(
              HttpMethod.PUT,
              getAbsolutePath(),
              updateClientId(portEntity),
              getHeaders(headersToOverride))
          .getResponse();
    }

    // handle expects request (usually from the cluster manager)
    final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
    if (expects != null) {
      serviceFacade.verifyUpdateInputPort(requestPortDTO);
      return generateContinueResponse().build();
    }

    // update the input port
    final RevisionDTO revision = portEntity.getRevision();
    final ConfigurationSnapshot<PortDTO> controllerResponse =
        serviceFacade.updateInputPort(
            new Revision(revision.getVersion(), revision.getClientId()), requestPortDTO);

    // get the results
    final PortDTO responsePortDTO = controllerResponse.getConfiguration();
    populateRemainingInputPortContent(responsePortDTO);

    // get the updated revision
    final RevisionDTO updatedRevision = new RevisionDTO();
    updatedRevision.setClientId(revision.getClientId());
    updatedRevision.setVersion(controllerResponse.getVersion());

    // build the response entity
    final InputPortEntity entity = new InputPortEntity();
    entity.setRevision(updatedRevision);
    entity.setInputPort(responsePortDTO);

    if (controllerResponse.isNew()) {
      return clusterContext(generateCreatedResponse(URI.create(responsePortDTO.getUri()), entity))
          .build();
    } else {
      return clusterContext(generateOkResponse(entity)).build();
    }
  }
Пример #15
0
  /**
   * Retrieves the specified template.
   *
   * @param id The id of the template to retrieve
   * @return A templateEntity.
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_XML)
  @Path("{id}/download")
  @ApiOperation(
      value = "Exports a template",
      response = TemplateDTO.class,
      authorizations = {@Authorization(value = "Read - /templates/{uuid}", type = "")})
  @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 exportTemplate(
      @ApiParam(value = "The template id.", required = true) @PathParam("id") final String id) {

    if (isReplicateRequest()) {
      return replicate(HttpMethod.GET);
    }

    // authorize access
    serviceFacade.authorizeAccess(
        lookup -> {
          final Authorizable template = lookup.getTemplate(id);
          template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
        });

    // get the template
    final TemplateDTO template = serviceFacade.exportTemplate(id);

    // prune the template id
    template.setId(null);

    // determine the name of the attachement - possible issues with spaces in file names
    String attachmentName = template.getName();
    if (StringUtils.isBlank(attachmentName)) {
      attachmentName = "template";
    } else {
      attachmentName = attachmentName.replaceAll("\\s", "_");
    }

    // generate the response
    /*
     * Here instead of relying on default JAXB marshalling we are simply
     * serializing template to String (formatted, indented etc) and sending
     * it as part of the response.
     */
    String serializedTemplate =
        new String(TemplateSerializer.serialize(template), StandardCharsets.UTF_8);
    return generateOkResponse(serializedTemplate)
        .header(
            "Content-Disposition", String.format("attachment; filename=\"%s.xml\"", attachmentName))
        .build();
  }
Пример #16
0
  /**
   * Removes the specified access policy.
   *
   * @param httpServletRequest request
   * @param version The revision is used to verify the client is working with the latest version of
   *     the flow.
   * @param clientId Optional client id. If the client id is not specified, a new one will be
   *     generated. This value (whether specified or generated) is included in the response.
   * @param id The id of the access policy to remove.
   * @return A entity containing the client id and an updated revision.
   */
  @DELETE
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
  @ApiOperation(
      value = "Deletes an access policy",
      response = AccessPolicyEntity.class,
      authorizations = {@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")})
  @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 removeAccessPolicy(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(
              value =
                  "The revision is used to verify the client is working with the latest version of the flow.",
              required = false)
          @QueryParam(VERSION)
          final LongParameter version,
      @ApiParam(
              value =
                  "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
              required = false)
          @QueryParam(CLIENT_ID)
          @DefaultValue(StringUtils.EMPTY)
          final ClientIdParameter clientId,
      @ApiParam(value = "The access policy id.", required = true) @PathParam("id")
          final String id) {

    if (isReplicateRequest()) {
      return replicate(HttpMethod.DELETE);
    }

    // handle expects request (usually from the cluster manager)
    final Revision revision =
        new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
    return withWriteLock(
        serviceFacade,
        revision,
        lookup -> {
          final Authorizable accessPolicy = lookup.getAccessPolicyById(id);
          accessPolicy.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
        },
        () -> {},
        () -> {
          // delete the specified access policy
          final AccessPolicyEntity entity = serviceFacade.deleteAccessPolicy(revision, id);
          return clusterContext(generateOkResponse(entity)).build();
        });
  }
Пример #17
0
  /**
   * Gets the system diagnostics for this NiFi instance.
   *
   * @return A systemDiagnosticsEntity.
   * @throws InterruptedException if interrupted
   */
  @GET
  @Consumes(MediaType.WILDCARD)
  @Produces(MediaType.APPLICATION_JSON)
  @ApiOperation(
      value = "Gets the diagnostics for the system NiFi is running on",
      response = SystemDiagnosticsEntity.class,
      authorizations = {@Authorization(value = "Read - /system", type = "")})
  @ApiResponses(
      value = {
        @ApiResponse(code = 401, message = "Client could not be authenticated."),
        @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
      })
  public Response getSystemDiagnostics(
      @ApiParam(
              value =
                  "Whether or not to include the breakdown per node. Optional, defaults to false",
              required = false)
          @QueryParam("nodewise")
          @DefaultValue(NODEWISE)
          final Boolean nodewise,
      @ApiParam(value = "The id of the node where to get the status.", required = false)
          @QueryParam("clusterNodeId")
          final String clusterNodeId)
      throws InterruptedException {

    authorizeSystem();

    // ensure a valid request
    if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
      throw new IllegalArgumentException(
          "Nodewise requests cannot be directed at a specific node.");
    }

    if (isReplicateRequest()) {
      // determine where this request should be sent
      if (clusterNodeId == null) {
        final NodeResponse nodeResponse;

        // Determine whether we should replicate only to the cluster coordinator, or if we should
        // replicate directly
        // to the cluster nodes themselves.
        if (getReplicationTarget() == ReplicationTarget.CLUSTER_NODES) {
          nodeResponse =
              getRequestReplicator()
                  .replicate(
                      HttpMethod.GET, getAbsolutePath(), getRequestParameters(), getHeaders())
                  .awaitMergedResponse();
        } else {
          nodeResponse =
              getRequestReplicator()
                  .forwardToCoordinator(
                      getClusterCoordinatorNode(),
                      HttpMethod.GET,
                      getAbsolutePath(),
                      getRequestParameters(),
                      getHeaders())
                  .awaitMergedResponse();
        }

        final SystemDiagnosticsEntity entity =
            (SystemDiagnosticsEntity) nodeResponse.getUpdatedEntity();

        // ensure there is an updated entity (result of merging) and prune the response as necessary
        if (entity != null && !nodewise) {
          entity.getSystemDiagnostics().setNodeSnapshots(null);
        }

        return nodeResponse.getResponse();
      } else {
        return replicate(HttpMethod.GET);
      }
    }

    final SystemDiagnosticsDTO systemDiagnosticsDto = serviceFacade.getSystemDiagnostics();

    // create the response
    final SystemDiagnosticsEntity entity = new SystemDiagnosticsEntity();
    entity.setSystemDiagnostics(systemDiagnosticsDto);

    // generate the response
    return clusterContext(generateOkResponse(entity)).build();
  }
Пример #18
0
  /**
   * Updates the specified output port.
   *
   * @param httpServletRequest request
   * @param id The id of the output port to update.
   * @param requestPortEntity A outputPortEntity.
   * @return A outputPortEntity.
   */
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("{id}")
  @ApiOperation(
      value = "Updates an output port",
      response = PortEntity.class,
      authorizations = {@Authorization(value = "Write - /output-ports/{uuid}", type = "")})
  @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 updateOutputPort(
      @Context final HttpServletRequest httpServletRequest,
      @ApiParam(value = "The output port id.", required = true) @PathParam("id") final String id,
      @ApiParam(value = "The output port configuration details.", required = true)
          final PortEntity requestPortEntity) {

    if (requestPortEntity == null || requestPortEntity.getComponent() == null) {
      throw new IllegalArgumentException("Output port details must be specified.");
    }

    if (requestPortEntity.getRevision() == null) {
      throw new IllegalArgumentException("Revision must be specified.");
    }

    // ensure the ids are the same
    PortDTO requestPortDTO = requestPortEntity.getComponent();
    if (!id.equals(requestPortDTO.getId())) {
      throw new IllegalArgumentException(
          String.format(
              "The output port id (%s) in the request body does not equal the "
                  + "output port id of the requested resource (%s).",
              requestPortDTO.getId(), id));
    }

    final PositionDTO proposedPosition = requestPortDTO.getPosition();
    if (proposedPosition != null) {
      if (proposedPosition.getX() == null || proposedPosition.getY() == null) {
        throw new IllegalArgumentException(
            "The x and y coordinate of the proposed position must be specified.");
      }
    }

    if (isReplicateRequest()) {
      return replicate(HttpMethod.PUT, requestPortEntity);
    }

    // handle expects request (usually from the cluster manager)
    final Revision requestRevision = getRevision(requestPortEntity, id);
    return withWriteLock(
        serviceFacade,
        requestPortEntity,
        requestRevision,
        lookup -> {
          Authorizable authorizable = lookup.getOutputPort(id);
          authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
        },
        () -> serviceFacade.verifyUpdateOutputPort(requestPortDTO),
        (revision, portEntity) -> {
          final PortDTO portDTO = portEntity.getComponent();

          // update the output port
          final PortEntity entity = serviceFacade.updateOutputPort(revision, portDTO);
          populateRemainingOutputPortEntityContent(entity);

          return clusterContext(generateOkResponse(entity)).build();
        });
  }