NIFI-2123: Add authorization of provenance events; refactor core classes so that Authorizable is located within nifi-api. This closes #592
Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/ae9e2fdf Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/ae9e2fdf Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/ae9e2fdf Branch: refs/heads/master Commit: ae9e2fdf0bfce31c38020784b78171709618903c Parents: 65d8958 Author: Mark Payne <[email protected]> Authored: Tue Jun 28 14:53:35 2016 -0400 Committer: Matt Gilman <[email protected]> Committed: Thu Jun 30 07:57:17 2016 -0400 ---------------------------------------------------------------------- .../authorization/AccessDeniedException.java | 39 ++ .../authorization/resource/Authorizable.java | 125 ++++++ .../nifi/authorization/user/NiFiUser.java | 44 ++ .../ProvenanceAuthorizableFactory.java | 35 ++ .../provenance/ProvenanceEventRepository.java | 98 +++-- .../nifi/provenance/ProvenanceEventType.java | 8 +- .../lineage/ComputeLineageSubmission.java | 5 + .../nifi/provenance/search/QuerySubmission.java | 5 + .../nifi/provenance/AsyncLineageSubmission.java | 9 +- .../nifi/provenance/AsyncQuerySubmission.java | 9 +- .../provenance/PlaceholderProvenanceEvent.java | 196 +++++++++ .../nifi/provenance/StandardLineageResult.java | 8 +- .../nifi/provenance/StandardQueryResult.java | 14 +- .../MockProvenanceEventRepository.java | 24 +- .../api/dto/provenance/lineage/LineageDTO.java | 15 - .../provenance/lineage/LineageRequestDTO.java | 13 + .../authorization/AccessDeniedException.java | 39 -- .../authorization/resource/Authorizable.java | 141 ------- .../resource/ProvenanceEventAuthorizable.java | 41 ++ .../authorization/resource/ResourceFactory.java | 25 +- .../authorization/resource/ResourceType.java | 1 + .../nifi/authorization/user/NiFiUser.java | 93 ----- .../authorization/user/StandardNiFiUser.java | 94 +++++ .../org/apache/nifi/controller/Template.java | 15 +- .../apache/nifi/controller/FlowController.java | 107 +++-- .../nifi/web/StandardNiFiServiceFacade.java | 2 +- .../StandardNiFiWebConfigurationContext.java | 18 +- .../nifi/web/api/AccessPolicyResource.java | 9 +- .../nifi/web/api/ApplicationResource.java | 4 +- .../apache/nifi/web/api/ConnectionResource.java | 7 +- .../nifi/web/api/ControllerServiceResource.java | 73 ++-- .../nifi/web/api/FlowFileQueueResource.java | 17 +- .../org/apache/nifi/web/api/FlowResource.java | 66 +-- .../org/apache/nifi/web/api/FunnelResource.java | 7 +- .../apache/nifi/web/api/InputPortResource.java | 7 +- .../org/apache/nifi/web/api/LabelResource.java | 7 +- .../apache/nifi/web/api/OutputPortResource.java | 7 +- .../nifi/web/api/ProcessGroupResource.java | 125 +++--- .../apache/nifi/web/api/ProcessorResource.java | 13 +- .../apache/nifi/web/api/ProvenanceResource.java | 8 +- .../web/api/RemoteProcessGroupResource.java | 11 +- .../nifi/web/api/ReportingTaskResource.java | 13 +- .../apache/nifi/web/api/SnippetResource.java | 3 +- .../apache/nifi/web/api/TemplateResource.java | 5 +- .../apache/nifi/web/api/TenantsResource.java | 21 +- .../api/config/AccessDeniedExceptionMapper.java | 8 +- .../org/apache/nifi/web/api/dto/DtoFactory.java | 7 +- .../nifi/web/controller/ControllerFacade.java | 96 ++--- .../web/dao/impl/StandardConnectionDAO.java | 4 +- .../web/StandardNiFiServiceFacadeSpec.groovy | 9 +- .../web/revision/TestNaiveRevisionManager.java | 7 +- .../anonymous/NiFiAnonymousUserFilter.java | 8 +- .../security/jwt/JwtAuthenticationProvider.java | 6 +- .../security/otp/OtpAuthenticationProvider.java | 3 +- .../security/token/NiFiAuthenticationToken.java | 5 + .../x509/X509AuthenticationProvider.java | 5 +- .../js/nf/provenance/nf-provenance-lineage.js | 8 +- .../js/nf/provenance/nf-provenance-table.js | 4 +- .../webapp/js/nf/provenance/nf-provenance.js | 25 +- .../src/main/webapp/js/nf/summary/nf-summary.js | 23 +- .../PersistentProvenanceRepository.java | 188 +++++++-- .../authorization/AuthorizationCheck.java | 24 ++ .../nifi/provenance/lucene/DocsReader.java | 13 +- .../nifi/provenance/lucene/IndexSearch.java | 10 +- .../nifi/provenance/lucene/LineageQuery.java | 7 +- .../TestPersistentProvenanceRepository.java | 400 +++++++++++++++++-- .../VolatileProvenanceRepository.java | 168 ++++++-- .../TestVolatileProvenanceRepository.java | 28 +- 68 files changed, 1832 insertions(+), 850 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java new file mode 100644 index 0000000..8712d28 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization; + +/** + * Represents any error that might occur while authorizing user requests. + */ +public class AccessDeniedException extends RuntimeException { + private static final long serialVersionUID = -5683444815269084134L; + + public AccessDeniedException(Throwable cause) { + super(cause); + } + + public AccessDeniedException(String message, Throwable cause) { + super(message, cause); + } + + public AccessDeniedException(String message) { + super(message); + } + + public AccessDeniedException() { + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java new file mode 100644 index 0000000..09fab19 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization.resource; + +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.AuthorizationRequest; +import org.apache.nifi.authorization.AuthorizationResult; +import org.apache.nifi.authorization.AuthorizationResult.Result; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.user.NiFiUser; + +public interface Authorizable { + + /** + * The parent for this Authorizable. May be null. + * + * @return the parent authorizable or null + */ + Authorizable getParentAuthorizable(); + + /** + * The Resource for this Authorizable. + * + * @return the parent resource + */ + Resource getResource(); + + /** + * Returns whether the current user is authorized for the specified action on the specified resource. This + * method does not imply the user is directly attempting to access the specified resource. If the user is + * attempting a direct access use Authorizable.authorize(). + * + * @param authorizer authorizer + * @param action action + * @return is authorized + */ + default boolean isAuthorized(Authorizer authorizer, RequestAction action, NiFiUser user) { + return Result.Approved.equals(checkAuthorization(authorizer, action, user).getResult()); + } + + /** + * Returns the result of an authorization request for the specified user for the specified action on the specified + * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is + * attempting a direct access use Authorizable.authorize(). + * + * @param authorizer authorizer + * @param action action + * @param user user + * @return is authorized + */ + default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user) { + // TODO - include user details context + + // build the request + final AuthorizationRequest request = new AuthorizationRequest.Builder() + .identity(user.getIdentity()) + .anonymous(user.isAnonymous()) + .accessAttempt(false) + .action(action) + .resource(getResource()) + .build(); + + // perform the authorization + final AuthorizationResult result = authorizer.authorize(request); + + // verify the results + if (Result.ResourceNotFound.equals(result.getResult())) { + final Authorizable parent = getParentAuthorizable(); + if (parent == null) { + return AuthorizationResult.denied(); + } else { + return parent.checkAuthorization(authorizer, action, user); + } + } else { + return result; + } + } + + /** + * Authorizes the current user for the specified action on the specified resource. This method does imply the user is + * directly accessing the specified resource. + * + * @param authorizer authorizer + * @param action action + */ + default void authorize(Authorizer authorizer, RequestAction action, NiFiUser user) throws AccessDeniedException { + // TODO - include user details context + + final AuthorizationRequest request = new AuthorizationRequest.Builder() + .identity(user.getIdentity()) + .anonymous(user.isAnonymous()) + .accessAttempt(true) + .action(action) + .resource(getResource()) + .build(); + + final AuthorizationResult result = authorizer.authorize(request); + if (Result.ResourceNotFound.equals(result.getResult())) { + final Authorizable parent = getParentAuthorizable(); + if (parent == null) { + throw new AccessDeniedException("Access is denied"); + } else { + parent.authorize(authorizer, action, user); + } + } else if (Result.Denied.equals(result.getResult())) { + throw new AccessDeniedException(result.getExplanation()); + } + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java new file mode 100644 index 0000000..d5dee54 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.nifi.authorization.user; + +/** + * A representation of a NiFi user that has logged into the application + */ +public interface NiFiUser { + + /** + * @return the unique identity of this user + */ + String getIdentity(); + + /** + * @return the user name for this user + */ + String getUserName(); + + /** + * @return the next user in the proxied entities chain, or <code>null</code> if no more users exist in the chain. + */ + NiFiUser getChain(); + + /** + * @return <code>true</code> if the user is the unauthenticated Anonymous user + */ + boolean isAnonymous(); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java new file mode 100644 index 0000000..23d6b3d --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceAuthorizableFactory.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.nifi.provenance; + +import org.apache.nifi.authorization.resource.Authorizable; +import org.apache.nifi.web.ResourceNotFoundException; + +public interface ProvenanceAuthorizableFactory { + + /** + * Generates an Authorizable object for the Provenance events of the component with the given ID + * + * @param componentId the ID of the component to which the Provenance events belong + * + * @return the Authorizable that can be use to authorize access to provenance events + * @throws ResourceNotFoundException if no component can be found with the given ID + */ + Authorizable createProvenanceAuthorizable(String componentId); + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java index 25563b7..235a1fa 100644 --- a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java +++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventRepository.java @@ -19,11 +19,15 @@ package org.apache.nifi.provenance; import java.io.IOException; import java.util.List; +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.events.EventReporter; import org.apache.nifi.provenance.lineage.ComputeLineageSubmission; import org.apache.nifi.provenance.search.Query; import org.apache.nifi.provenance.search.QuerySubmission; import org.apache.nifi.provenance.search.SearchableField; +import org.apache.nifi.web.ResourceNotFoundException; /** * This Repository houses Provenance Events. The repository is responsible for @@ -38,9 +42,12 @@ public interface ProvenanceEventRepository { * framework. * * @param eventReporter to report to + * @param authorizer the authorizer to use for authorizing individual events + * @param resourceFactory the resource factory to use for generating Provenance Resource objects for authorization purposes + * * @throws java.io.IOException if unable to initialize */ - void initialize(EventReporter eventReporter) throws IOException; + void initialize(EventReporter eventReporter, Authorizer authorizer, ProvenanceAuthorizableFactory resourceFactory) throws IOException; /** * Returns a {@link ProvenanceEventBuilder} that is capable of building @@ -74,7 +81,8 @@ public interface ProvenanceEventRepository { /** * Returns a List of all <code>ProvenanceEventRecord</code>s in the * repository starting with the given ID. The first ID in the repository - * will always be 0 or higher. + * will always be 0 or higher. This method performs no authorization of + * the events. * * @param firstRecordId id of the first record to retrieve * @param maxRecords maximum number of records to retrieve @@ -84,8 +92,24 @@ public interface ProvenanceEventRepository { List<ProvenanceEventRecord> getEvents(long firstRecordId, final int maxRecords) throws IOException; /** + * Returns a List of all <code>ProvenanceEventRecord</code>s in the + * repository starting with the given ID. The first ID in the repository + * will always be 0 or higher. Each event that is found will be authorized + * against the given NiFiUser. If the user does not have authorization for + * the event, the event will not be returned. + * + * @param firstRecordId id of the first record to retrieve + * @param maxRecords maximum number of records to retrieve + * @param user the NiFi user that the events should be authorized against + * + * @return records + * @throws java.io.IOException if error reading from repository + */ + List<ProvenanceEventRecord> getEvents(long firstRecordId, final int maxRecords, NiFiUser user) throws IOException; + + /** * @return the largest ID of any event that is queryable in the repository. - * If no queryable events exists, returns null + * If no queryable events exists, returns null */ Long getMaxEventId(); @@ -94,70 +118,96 @@ public interface ProvenanceEventRepository { * identifier that can be used to fetch the results at a later time * * @param query to submit + * @param user the NiFi User to authorize the events against + * * @return an identifier that can be used to fetch the results at a later - * time + * time */ - QuerySubmission submitQuery(Query query); + QuerySubmission submitQuery(Query query, NiFiUser user); /** * @param queryIdentifier of the query + * @param user the user who is retrieving the query * * @return the QueryResult associated with the given identifier, if the - * query has finished processing. If the query has not yet finished running, - * returns <code>null</code> + * query has finished processing. If the query has not yet finished running, + * returns <code>null</code> */ - QuerySubmission retrieveQuerySubmission(String queryIdentifier); + QuerySubmission retrieveQuerySubmission(String queryIdentifier, NiFiUser user); /** * Submits a Lineage Computation to be completed and returns the * AsynchronousLineageResult that indicates the status of the request and - * the results, if the computation is complete. + * the results, if the computation is complete. If the given user does not + * have authorization to view one of the events in the lineage, a placeholder + * event will be used instead that provides none of the event details except + * for the identifier of the component that emitted the Provenance Event. It is + * necessary to include this node in the lineage view so that the lineage makes + * sense, rather than showing disconnected graphs when the user is not authorized + * for all components' provenance events. * * @param flowFileUuid the UUID of the FlowFile for which the Lineage should - * be calculated + * be calculated + * @param user the NiFi User to authorize events against + * * @return a {@link ComputeLineageSubmission} object that can be used to - * check if the computing is complete and if so get the results + * check if the computing is complete and if so get the results */ - ComputeLineageSubmission submitLineageComputation(String flowFileUuid); + ComputeLineageSubmission submitLineageComputation(String flowFileUuid, NiFiUser user); /** * @param lineageIdentifier identifier of lineage to compute + * @param user the user who is retrieving the lineage submission + * * @return the {@link ComputeLineageSubmission} associated with the given - * identifier + * identifier */ - ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier); + ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier, NiFiUser user); /** + * Retrieves the Provenance Event with the given ID. The event will be returned only + * if the given user is authorized to access the event. Otherwise, an + * AccessDeniedException or ResourceNotFoundException will be thrown, as appropriate + * * @param id to lookup * @return the Provenance Event Record with the given ID, if it exists, or - * {@code null} otherwise + * {@code null} otherwise * @throws IOException if failure while retrieving event + * @throws AccessDeniedException if the user does not have access to the component + * @throws ResourceNotFoundException if the component that the event belongs to cannot be found */ - ProvenanceEventRecord getEvent(long id) throws IOException; + ProvenanceEventRecord getEvent(long id, NiFiUser user) throws IOException; /** - * Submits a request to expand the parents of the event with the given id + * Submits a request to expand the parents of the event with the given id. If the given user + * is not authorized to access any event, a placeholder will be used instead that contains only + * the ID of the component that emitted the event. * * @param eventId the one-up id of the Event to expand + * @param user the NiFi user to authorize events against * @return a submission which can be checked for status * * @throws IllegalArgumentException if the given identifier identifies a - * Provenance Event that has a Type that is not expandable or if the - * identifier cannot be found + * Provenance Event that has a Type that is not expandable or if the + * identifier cannot be found */ - ComputeLineageSubmission submitExpandParents(long eventId); + ComputeLineageSubmission submitExpandParents(long eventId, NiFiUser user); /** - * Submits a request to expand the children of the event with the given id + * Submits a request to expand the children of the event with the given id. If the given user + * is not authorized to access any event, a placeholder will be used instead that contains only + * the ID of the component that emitted the event. * * @param eventId the one-up id of the Event + * @param user the NiFi user to authorize events against + * * @return a submission which can be checked for status * * @throws IllegalArgumentException if the given identifier identifies a - * Provenance Event that has a Type that is not expandable or if the - * identifier cannot be found + * Provenance Event that has a Type that is not expandable or if the + * identifier cannot be found */ - ComputeLineageSubmission submitExpandChildren(long eventId); + ComputeLineageSubmission submitExpandChildren(long eventId, NiFiUser user); /** * Closes the repository, freeing any resources http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java index 0d844b8..756d362 100644 --- a/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java +++ b/nifi-api/src/main/java/org/apache/nifi/provenance/ProvenanceEventType.java @@ -117,5 +117,11 @@ public enum ProvenanceEventType { * that is the UUID of the a newly created FlowFile that will be re-queued * for processing. */ - REPLAY + REPLAY, + + /** + * Indicates that the type of the provenance event is unknown because the user + * who is attempting to access the event is not authorize to know the type. + */ + UNKNOWN; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java b/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java index a9df26c..8a11523 100644 --- a/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java +++ b/nifi-api/src/main/java/org/apache/nifi/provenance/lineage/ComputeLineageSubmission.java @@ -34,6 +34,11 @@ public interface ComputeLineageSubmission { Date getSubmissionTime(); /** + * @return the identity of the user who submitted the request + */ + String getSubmitterIdentity(); + + /** * @return the generated identifier for this lineage result */ String getLineageIdentifier(); http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java b/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java index 4716d2d..45efe4b 100644 --- a/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java +++ b/nifi-api/src/main/java/org/apache/nifi/provenance/search/QuerySubmission.java @@ -52,4 +52,9 @@ public interface QuerySubmission { * <code>false</code> otherwise */ boolean isCanceled(); + + /** + * @return the identity of the user who submitted the query + */ + String getSubmitterIdentity(); } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java index 4a52a89..82bb542 100644 --- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java +++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncLineageSubmission.java @@ -34,19 +34,26 @@ public class AsyncLineageSubmission implements ComputeLineageSubmission { private final LineageComputationType computationType; private final Long eventId; private final Collection<String> lineageFlowFileUuids; + private final String submitterId; private volatile boolean canceled = false; private final StandardLineageResult result; - public AsyncLineageSubmission(final LineageComputationType computationType, final Long eventId, final Collection<String> lineageFlowFileUuids, final int numSteps) { + public AsyncLineageSubmission(final LineageComputationType computationType, final Long eventId, final Collection<String> lineageFlowFileUuids, final int numSteps, final String submitterId) { this.computationType = computationType; this.eventId = eventId; this.lineageFlowFileUuids = lineageFlowFileUuids; + this.submitterId = submitterId; this.result = new StandardLineageResult(numSteps, lineageFlowFileUuids); } @Override + public String getSubmitterIdentity() { + return submitterId; + } + + @Override public StandardLineageResult getResult() { return result; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java index 00c6170..cd2ab39 100644 --- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java +++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/AsyncQuerySubmission.java @@ -31,6 +31,7 @@ public class AsyncQuerySubmission implements QuerySubmission { private volatile boolean canceled = false; private final StandardQueryResult queryResult; + private final String submitterId; /** * Constructs an AsyncQuerySubmission with the given query and the given @@ -40,12 +41,18 @@ public class AsyncQuerySubmission implements QuerySubmission { * @param query the query to execute * @param numSteps how many steps to include */ - public AsyncQuerySubmission(final Query query, final int numSteps) { + public AsyncQuerySubmission(final Query query, final int numSteps, final String submitterId) { this.query = query; + this.submitterId = submitterId; queryResult = new StandardQueryResult(query, numSteps); } @Override + public String getSubmitterIdentity() { + return submitterId; + } + + @Override public Date getSubmissionTime() { return submissionTime; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java new file mode 100644 index 0000000..bc40302 --- /dev/null +++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/PlaceholderProvenanceEvent.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.nifi.provenance; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A Provenance Event that is used to replace another Provenance Event when authorizations + * are not granted for the original Provenance Event + */ +public class PlaceholderProvenanceEvent implements ProvenanceEventRecord { + private final String componentId; + private final long eventId; + private final long eventTime; + private final String flowFileUuid; + + public PlaceholderProvenanceEvent(final ProvenanceEventRecord original) { + this.componentId = original.getComponentId(); + this.eventId = original.getEventId(); + this.eventTime = original.getEventTime(); + this.flowFileUuid = original.getFlowFileUuid(); + } + + @Override + public long getEventId() { + return eventId; + } + + @Override + public long getEventTime() { + return eventTime; + } + + @Override + public long getFlowFileEntryDate() { + return 0; + } + + @Override + public long getLineageStartDate() { + return 0; + } + + @Override + public Set<String> getLineageIdentifiers() { + return Collections.emptySet(); + } + + @Override + public long getFileSize() { + return -1L; + } + + @Override + public Long getPreviousFileSize() { + return -1L; + } + + @Override + public long getEventDuration() { + return -1L; + } + + @Override + public ProvenanceEventType getEventType() { + return ProvenanceEventType.UNKNOWN; + } + + @Override + public Map<String, String> getAttributes() { + return Collections.emptyMap(); + } + + @Override + public Map<String, String> getPreviousAttributes() { + return Collections.emptyMap(); + } + + @Override + public Map<String, String> getUpdatedAttributes() { + return Collections.emptyMap(); + } + + @Override + public String getComponentId() { + return componentId; + } + + @Override + public String getComponentType() { + return null; + } + + @Override + public String getTransitUri() { + return null; + } + + @Override + public String getSourceSystemFlowFileIdentifier() { + return null; + } + + @Override + public String getFlowFileUuid() { + return flowFileUuid; + } + + @Override + public List<String> getParentUuids() { + return null; + } + + @Override + public List<String> getChildUuids() { + return null; + } + + @Override + public String getAlternateIdentifierUri() { + return null; + } + + @Override + public String getDetails() { + return null; + } + + @Override + public String getRelationship() { + return null; + } + + @Override + public String getSourceQueueIdentifier() { + return null; + } + + @Override + public String getContentClaimSection() { + return null; + } + + @Override + public String getPreviousContentClaimSection() { + return null; + } + + @Override + public String getContentClaimContainer() { + return null; + } + + @Override + public String getPreviousContentClaimContainer() { + return null; + } + + @Override + public String getContentClaimIdentifier() { + return null; + } + + @Override + public String getPreviousContentClaimIdentifier() { + return null; + } + + @Override + public Long getContentClaimOffset() { + return null; + } + + @Override + public Long getPreviousContentClaimOffset() { + return null; + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java index 02c089d..78b3188 100644 --- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java +++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardLineageResult.java @@ -268,7 +268,7 @@ public class StandardLineageResult implements ComputeLineageResult { final boolean isNewFlowFile = nodes.add(childNode); if (!isNewFlowFile) { final String msg = "Unable to generate Lineage Graph because multiple " - + "events were registered claiming to have generated the same FlowFile (UUID = " + childNode.getFlowFileUuid() + ")"; + + "events were registered claiming to have generated the same FlowFile (UUID = " + childNode.getFlowFileUuid() + ")"; logger.error(msg); setError(msg); return; @@ -287,7 +287,7 @@ public class StandardLineageResult implements ComputeLineageResult { lastEventMap.put(parentUuid, lineageNode); } } - break; + break; case RECEIVE: case CREATE: { // for a receive event, we want to create a FlowFile Node that represents the FlowFile received @@ -296,7 +296,7 @@ public class StandardLineageResult implements ComputeLineageResult { final boolean isNewFlowFile = nodes.add(flowFileNode); if (!isNewFlowFile) { final String msg = "Found cycle in graph. This indicates that multiple events " - + "were registered claiming to have generated the same FlowFile (UUID = " + flowFileNode.getFlowFileUuid() + ")"; + + "were registered claiming to have generated the same FlowFile (UUID = " + flowFileNode.getFlowFileUuid() + ")"; setError(msg); logger.error(msg); return; @@ -304,7 +304,7 @@ public class StandardLineageResult implements ComputeLineageResult { edges.add(new EdgeNode(record.getFlowFileUuid(), lineageNode, flowFileNode)); lastEventMap.put(record.getFlowFileUuid(), flowFileNode); } - break; + break; default: break; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java index 03ab3ea..5c09e8e 100644 --- a/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java +++ b/nifi-commons/nifi-data-provenance-utils/src/main/java/org/apache/nifi/provenance/StandardQueryResult.java @@ -90,7 +90,19 @@ public class StandardQueryResult implements QueryResult { public long getTotalHitCount() { readLock.lock(); try { - return totalHitCount; + // Because we filter the results based on the user's permissions, + // we don't want to indicate that the total hit count is 1,000+ when we + // have 0 matching records, for instance. So, if we have fewer matching + // records than the max specified by the query, it is either the case that + // we truly don't have enough records to reach the max results, or that + // the user is not authorized to see some of the results. Either way, + // we want to report the number of events that we find AND that the user + // is allowed to see, so we report matching record count, or up to max results. + if (matchingRecords.size() < query.getMaxResults()) { + return matchingRecords.size(); + } else { + return query.getMaxResults(); + } } finally { readLock.unlock(); } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java ---------------------------------------------------------------------- diff --git a/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java b/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java index 241041a..dc71ed5 100644 --- a/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java +++ b/nifi-mock/src/main/java/org/apache/nifi/provenance/MockProvenanceEventRepository.java @@ -22,6 +22,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.events.EventReporter; import org.apache.nifi.provenance.lineage.ComputeLineageSubmission; import org.apache.nifi.provenance.search.Query; @@ -54,7 +56,8 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository } @Override - public void initialize(EventReporter reporter) throws IOException { + public void initialize(EventReporter eventReporter, Authorizer authorizer, ProvenanceAuthorizableFactory resourceFactory) throws IOException { + } @Override @@ -67,32 +70,37 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository } @Override + public List<ProvenanceEventRecord> getEvents(long firstRecordId, int maxRecords, NiFiUser user) throws IOException { + return getEvents(firstRecordId, maxRecords); + } + + @Override public Long getMaxEventId() { return Long.valueOf(records.size() - 1); } @Override - public QuerySubmission submitQuery(Query query) { + public QuerySubmission submitQuery(Query query, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support querying"); } @Override - public QuerySubmission retrieveQuerySubmission(String queryIdentifier) { + public QuerySubmission retrieveQuerySubmission(String queryIdentifier, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support querying"); } @Override - public ComputeLineageSubmission submitLineageComputation(String flowFileUuid) { + public ComputeLineageSubmission submitLineageComputation(String flowFileUuid, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation"); } @Override - public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier) { + public ComputeLineageSubmission retrieveLineageSubmission(String lineageIdentifier, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation"); } @Override - public ProvenanceEventRecord getEvent(long id) throws IOException { + public ProvenanceEventRecord getEvent(long id, NiFiUser user) throws IOException { if (id > records.size()) { return null; } @@ -101,12 +109,12 @@ public class MockProvenanceEventRepository implements ProvenanceEventRepository } @Override - public ComputeLineageSubmission submitExpandParents(long eventId) { + public ComputeLineageSubmission submitExpandParents(long eventId, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation"); } @Override - public ComputeLineageSubmission submitExpandChildren(long eventId) { + public ComputeLineageSubmission submitExpandChildren(long eventId, NiFiUser user) { throw new UnsupportedOperationException("MockProvenanceEventRepository does not support Lineage Computation"); } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java index bc68d78..46d99bf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java @@ -30,7 +30,6 @@ public class LineageDTO { private String id; private String uri; - private String clusterNodeId; private Date submissionTime; private Date expiration; @@ -69,20 +68,6 @@ public class LineageDTO { } /** - * @return id of the node in the cluster where this lineage originated - */ - @ApiModelProperty( - value = "The id of the node where this lineage originated if clustered." - ) - public String getClusterNodeId() { - return clusterNodeId; - } - - public void setClusterNodeId(String clusterNodeId) { - this.clusterNodeId = clusterNodeId; - } - - /** * @return submission time for this lineage */ @XmlJavaTypeAdapter(TimestampAdapter.class) http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java index afab621..5a59a7c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java @@ -41,6 +41,7 @@ public class LineageRequestDTO { private LineageRequestType lineageRequestType; private String uuid; + private String clusterNodeId; /** * @return event id that was used to generate this lineage @@ -74,6 +75,18 @@ public class LineageRequestDTO { } /** + * @return id of the node in the cluster where this lineage originated + */ + @ApiModelProperty(value = "The id of the node where this lineage originated if clustered.") + public String getClusterNodeId() { + return clusterNodeId; + } + + public void setClusterNodeId(String clusterNodeId) { + this.clusterNodeId = clusterNodeId; + } + + /** * @return uuid that was used to generate this lineage */ @ApiModelProperty( http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java deleted file mode 100644 index 092e80c..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.authorization; - -/** - * Represents any error that might occur while authorizing user requests. - */ -public class AccessDeniedException extends RuntimeException { - - public AccessDeniedException(Throwable cause) { - super(cause); - } - - public AccessDeniedException(String message, Throwable cause) { - super(message, cause); - } - - public AccessDeniedException(String message) { - super(message); - } - - public AccessDeniedException() { - } - -} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java deleted file mode 100644 index 50f7288..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.authorization.resource; - -import org.apache.nifi.authorization.AccessDeniedException; -import org.apache.nifi.authorization.AuthorizationRequest; -import org.apache.nifi.authorization.AuthorizationResult; -import org.apache.nifi.authorization.AuthorizationResult.Result; -import org.apache.nifi.authorization.Authorizer; -import org.apache.nifi.authorization.RequestAction; -import org.apache.nifi.authorization.Resource; -import org.apache.nifi.authorization.user.NiFiUser; -import org.apache.nifi.authorization.user.NiFiUserUtils; - -public interface Authorizable { - - /** - * The parent for this Authorizable. May be null. - * - * @return the parent authorizable or null - */ - Authorizable getParentAuthorizable(); - - /** - * The Resource for this Authorizable. - * - * @return the parent resource - */ - Resource getResource(); - - /** - * Returns whether the current user is authorized for the specified action on the specified resource. This - * method does not imply the user is directly attempting to access the specified resource. If the user is - * attempting a direct access use Authorizable.authorize(). - * - * @param authorizer authorizer - * @param action action - * @return is authorized - */ - default boolean isAuthorized(Authorizer authorizer, RequestAction action) { - return Result.Approved.equals(checkAuthorization(authorizer, action).getResult()); - } - - /** - * Returns the result of an authorization request for the current user for the specified action on the specified - * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is - * attempting a direct access use Authorizable.authorize(). - * - * @param authorizer authorizer - * @param action action - * @return is authorized - */ - default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action) { - return checkAuthorization(authorizer, action, NiFiUserUtils.getNiFiUser()); - } - - /** - * Returns the result of an authorization request for the specified user for the specified action on the specified - * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is - * attempting a direct access use Authorizable.authorize(). - * - * @param authorizer authorizer - * @param action action - * @param user user - * @return is authorized - */ - default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user) { - // TODO - include user details context - - // build the request - final AuthorizationRequest request = new AuthorizationRequest.Builder() - .identity(user.getIdentity()) - .anonymous(user.isAnonymous()) - .accessAttempt(false) - .action(action) - .resource(getResource()) - .build(); - - // perform the authorization - final AuthorizationResult result = authorizer.authorize(request); - - // verify the results - if (Result.ResourceNotFound.equals(result.getResult())) { - final Authorizable parent = getParentAuthorizable(); - if (parent == null) { - return AuthorizationResult.denied(); - } else { - return parent.checkAuthorization(authorizer, action); - } - } else { - return result; - } - } - - /** - * Authorizes the current user for the specified action on the specified resource. This method does imply the user is - * directly accessing the specified resource. - * - * @param authorizer authorizer - * @param action action - */ - default void authorize(Authorizer authorizer, RequestAction action) throws AccessDeniedException { - final NiFiUser user = NiFiUserUtils.getNiFiUser(); - - // TODO - include user details context - - final AuthorizationRequest request = new AuthorizationRequest.Builder() - .identity(user.getIdentity()) - .anonymous(user.isAnonymous()) - .accessAttempt(true) - .action(action) - .resource(getResource()) - .build(); - - final AuthorizationResult result = authorizer.authorize(request); - if (Result.ResourceNotFound.equals(result.getResult())) { - final Authorizable parent = getParentAuthorizable(); - if (parent == null) { - throw new AccessDeniedException("Access is denied"); - } else { - parent.authorize(authorizer, action); - } - } else if (Result.Denied.equals(result.getResult())) { - throw new AccessDeniedException(result.getExplanation()); - } - } -} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java new file mode 100644 index 0000000..153047e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ProvenanceEventAuthorizable.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization.resource; + +import org.apache.nifi.authorization.Resource; + +public class ProvenanceEventAuthorizable implements Authorizable { + final Authorizable authorizable; + + public ProvenanceEventAuthorizable(final Authorizable authorizable) { + this.authorizable = authorizable; + } + + @Override + public Authorizable getParentAuthorizable() { + if (authorizable.getParentAuthorizable() == null) { + return null; + } else { + return new ProvenanceEventAuthorizable(authorizable.getParentAuthorizable()); + } + } + + @Override + public Resource getResource() { + return ResourceFactory.getProvenanceEventResource(authorizable.getResource()); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java index 5fc56af..058a1c8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java @@ -179,6 +179,18 @@ public final class ResourceFactory { } }; + private final static Resource PROVENANCE_EVENT_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return ResourceType.ProvenanceEvent.getValue(); + } + + @Override + public String getName() { + return "Provenance Event"; + } + }; + private final static Resource PROXY_RESOURCE = new Resource() { @Override public String getIdentifier() { @@ -581,22 +593,19 @@ public final class ResourceFactory { /** * Gets a Resource for accessing a component's provenance events. * - * @param resourceType The type of resource being accessed - * @param identifier The identifier of the component being accessed - * @param name The name of the component being accessed - * @return The resource + * @param resource The resource for the component being accessed + * @return The resource for the provenance of the component being accessed */ - public static Resource getComponentProvenanceResource(final ResourceType resourceType, final String identifier, final String name) { - final Resource componentResource = getComponentResource(resourceType, identifier, name); + public static Resource getProvenanceEventResource(final Resource resource) { return new Resource() { @Override public String getIdentifier() { - return String.format("%s/%s", componentResource.getIdentifier(), "provenance"); + return String.format("%s%s", PROVENANCE_EVENT_RESOURCE.getIdentifier(), resource.getIdentifier()); } @Override public String getName() { - return componentResource.getName() + " provenance"; + return "Provenance Events for " + resource.getName(); } }; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java index eb08cec..1464cab 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java @@ -30,6 +30,7 @@ public enum ResourceType { Processor("/processors"), ProcessGroup("/process-groups"), Provenance("/provenance"), + ProvenanceEvent("/provenance-events"), Proxy("/proxy"), RemoteProcessGroup("/remote-process-groups"), ReportingTask("/reporting-tasks"), http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java deleted file mode 100644 index f560cd7..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.authorization.user; - -import java.io.Serializable; -import java.util.Objects; - -/** - * An NiFiUser. - */ -public class NiFiUser implements Serializable { - - public static final NiFiUser ANONYMOUS = new NiFiUser("anonymous"); - - private String identity; - private String userName; - - private NiFiUser chain; - - public NiFiUser(String identity) { - this(identity, identity, null); - } - - public NiFiUser(String identity, NiFiUser chain) { - this(identity, identity, chain); - } - - public NiFiUser(String identity, String userName, NiFiUser chain) { - this.identity = identity; - this.userName = userName; - this.chain = chain; - } - - /* getters / setters */ - - public String getIdentity() { - return identity; - } - - public String getUserName() { - return userName; - } - - public NiFiUser getChain() { - return chain; - } - - public boolean isAnonymous() { - return this == ANONYMOUS; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final NiFiUser other = (NiFiUser) obj; - if (!Objects.equals(this.identity, other.identity)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.identity); - return hash; - } - - @Override - public String toString() { - return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", "); - } - -} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java new file mode 100644 index 0000000..8c41a1f --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.authorization.user; + +import java.io.Serializable; +import java.util.Objects; + +/** + * An implementation of NiFiUser. + */ +public class StandardNiFiUser implements NiFiUser, Serializable { + private static final long serialVersionUID = -5503790026187817496L; + + public static final StandardNiFiUser ANONYMOUS = new StandardNiFiUser("anonymous"); + + private final String identity; + private final String userName; + private final NiFiUser chain; + + public StandardNiFiUser(String identity) { + this(identity, identity, null); + } + + public StandardNiFiUser(String identity, NiFiUser chain) { + this(identity, identity, chain); + } + + public StandardNiFiUser(String identity, String userName, NiFiUser chain) { + this.identity = identity; + this.userName = userName; + this.chain = chain; + } + + + @Override + public String getIdentity() { + return identity; + } + + @Override + public String getUserName() { + return userName; + } + + @Override + public NiFiUser getChain() { + return chain; + } + + @Override + public boolean isAnonymous() { + return this == ANONYMOUS; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (!(obj instanceof NiFiUser)) { + return false; + } + + final NiFiUser other = (NiFiUser) obj; + return Objects.equals(this.identity, other.getIdentity()); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 53 * hash + Objects.hashCode(this.identity); + return hash; + } + + @Override + public String toString() { + return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", "); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java index b9fd0cb..e50fe39 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java @@ -30,7 +30,6 @@ import org.apache.nifi.authorization.resource.Authorizable; import org.apache.nifi.authorization.resource.ResourceFactory; import org.apache.nifi.authorization.resource.ResourceType; import org.apache.nifi.authorization.user.NiFiUser; -import org.apache.nifi.authorization.user.NiFiUserUtils; import org.apache.nifi.connectable.Connection; import org.apache.nifi.controller.label.Label; import org.apache.nifi.groups.ProcessGroup; @@ -139,8 +138,8 @@ public class Template implements Authorizable { } @Override - public void authorize(final Authorizer authorizer, final RequestAction action) throws AccessDeniedException { - final AuthorizationResult result = checkAuthorization(authorizer, action, true); + public void authorize(final Authorizer authorizer, final RequestAction action, final NiFiUser user) throws AccessDeniedException { + final AuthorizationResult result = checkAuthorization(authorizer, action, true, user); if (Result.Denied.equals(result)) { final String explanation = result.getExplanation() == null ? "Access is denied" : result.getExplanation(); throw new AccessDeniedException(explanation); @@ -148,13 +147,11 @@ public class Template implements Authorizable { } @Override - public AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action) { - return checkAuthorization(authorizer, action, false); + public AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final NiFiUser user) { + return checkAuthorization(authorizer, action, false, user); } - private AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final boolean accessAttempt) { - final NiFiUser user = NiFiUserUtils.getNiFiUser(); - + private AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final boolean accessAttempt, final NiFiUser user) { // TODO - include user details context // build the request @@ -172,7 +169,7 @@ public class Template implements Authorizable { // verify the results if (Result.ResourceNotFound.equals(result.getResult())) { for (final Authorizable child : getAuthorizableComponents()) { - final AuthorizationResult childResult = child.checkAuthorization(authorizer, action); + final AuthorizationResult childResult = child.checkAuthorization(authorizer, action, user); if (Result.Denied.equals(childResult)) { return childResult; } http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java index c68c734..3d2eca2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java @@ -16,7 +16,39 @@ */ package org.apache.nifi.controller; -import com.sun.jersey.api.client.ClientHandlerException; +import static java.util.Objects.requireNonNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.net.ssl.SSLContext; + import org.apache.commons.lang3.StringUtils; import org.apache.nifi.action.Action; import org.apache.nifi.admin.service.AuditService; @@ -29,7 +61,9 @@ import org.apache.nifi.annotation.notification.PrimaryNodeState; import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.Resource; import org.apache.nifi.authorization.resource.Authorizable; +import org.apache.nifi.authorization.resource.ProvenanceEventAuthorizable; import org.apache.nifi.authorization.resource.ResourceFactory; +import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.cluster.HeartbeatPayload; import org.apache.nifi.cluster.coordination.heartbeat.HeartbeatMonitor; import org.apache.nifi.cluster.coordination.node.ClusterRoles; @@ -151,6 +185,7 @@ import org.apache.nifi.processor.StandardValidationContextFactory; import org.apache.nifi.provenance.ProvenanceEventRecord; import org.apache.nifi.provenance.ProvenanceEventRepository; import org.apache.nifi.provenance.ProvenanceEventType; +import org.apache.nifi.provenance.ProvenanceAuthorizableFactory; import org.apache.nifi.provenance.StandardProvenanceEventRecord; import org.apache.nifi.remote.HttpRemoteSiteListener; import org.apache.nifi.remote.RemoteGroupPort; @@ -178,6 +213,7 @@ import org.apache.nifi.stream.io.StreamUtils; import org.apache.nifi.util.FormatUtils; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.ReflectionUtils; +import org.apache.nifi.web.ResourceNotFoundException; import org.apache.nifi.web.api.dto.ConnectableDTO; import org.apache.nifi.web.api.dto.ConnectionDTO; import org.apache.nifi.web.api.dto.ControllerServiceDTO; @@ -198,39 +234,9 @@ import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLContext; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.LockSupport; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import static java.util.Objects.requireNonNull; +import com.sun.jersey.api.client.ClientHandlerException; -public class FlowController implements EventAccess, ControllerServiceProvider, ReportingTaskProvider, QueueProvider, Authorizable { +public class FlowController implements EventAccess, ControllerServiceProvider, ReportingTaskProvider, QueueProvider, Authorizable, ProvenanceAuthorizableFactory { // default repository implementations public static final String DEFAULT_FLOWFILE_REPO_IMPLEMENTATION = "org.apache.nifi.controller.repository.WriteAheadFlowFileRepository"; @@ -437,7 +443,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R try { this.provenanceEventRepository = createProvenanceRepository(properties); - this.provenanceEventRepository.initialize(createEventReporter(bulletinRepository)); + this.provenanceEventRepository.initialize(createEventReporter(bulletinRepository), authorizer, this); } catch (final Exception e) { throw new RuntimeException("Unable to create Provenance Repository", e); } @@ -3575,17 +3581,17 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R return null; } - public ProvenanceEventRecord replayFlowFile(final long provenanceEventRecordId, final String requestor) throws IOException { - final ProvenanceEventRecord record = provenanceEventRepository.getEvent(provenanceEventRecordId); + public ProvenanceEventRecord replayFlowFile(final long provenanceEventRecordId, final NiFiUser user) throws IOException { + final ProvenanceEventRecord record = provenanceEventRepository.getEvent(provenanceEventRecordId, user); if (record == null) { throw new IllegalStateException("Cannot find Provenance Event with ID " + provenanceEventRecordId); } - return replayFlowFile(record, requestor); + return replayFlowFile(record, user); } @SuppressWarnings("deprecation") - public ProvenanceEventRecord replayFlowFile(final ProvenanceEventRecord event, final String requestor) throws IOException { + public ProvenanceEventRecord replayFlowFile(final ProvenanceEventRecord event, final NiFiUser user) throws IOException { if (event == null) { throw new NullPointerException(); } @@ -3684,7 +3690,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R .setFlowFileUUID(parentUUID) .setAttributes(Collections.<String, String> emptyMap(), flowFileRecord.getAttributes()) .setCurrentContentClaim(event.getContentClaimContainer(), event.getContentClaimSection(), event.getContentClaimIdentifier(), event.getContentClaimOffset(), event.getFileSize()) - .setDetails("Replay requested by " + requestor) + .setDetails("Replay requested by " + user.getIdentity()) .setEventTime(System.currentTimeMillis()) .setFlowFileEntryDate(System.currentTimeMillis()) .setLineageStartDate(event.getLineageStartDate()) @@ -3847,6 +3853,29 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R } @Override + public Authorizable createProvenanceAuthorizable(final String componentId) { + final String rootGroupId = getRootGroupId(); + + // Provenance Events are generated only by connectable components, with the exception of DOWNLOAD events, + // which have the root process group's identifier assigned as the component ID. So, we check if the component ID + // is set to the root group and otherwise assume that the ID is that of a component. + final ProvenanceEventAuthorizable authorizable; + if (rootGroupId.equals(componentId)) { + authorizable = new ProvenanceEventAuthorizable(rootGroup); + } else { + final Connectable connectable = rootGroup.findConnectable(componentId); + + if (connectable == null) { + throw new ResourceNotFoundException("The component that generated this event is no longer part of the data flow."); + } + + authorizable = new ProvenanceEventAuthorizable(connectable); + } + + return authorizable; + } + + @Override public List<Action> getFlowChanges(final int firstActionId, final int maxActions) { final History history = auditService.getActions(firstActionId, maxActions); return new ArrayList<>(history.getActions()); http://git-wip-us.apache.org/repos/asf/nifi/blob/ae9e2fdf/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index eb8ea20..180b6bc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -2812,7 +2812,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } // perform the authorization - final AuthorizationResult result = authorizable.checkAuthorization(authorizer, RequestAction.READ); + final AuthorizationResult result = authorizable.checkAuthorization(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()); return Result.Approved.equals(result.getResult()); }
