mirror of
https://github.com/apache/nifi.git
synced 2025-02-06 01:58:32 +00:00
NIFI-4885:
- Introducing more granular restricted component access policies. This closes #2515. Signed-off-by: Mark Payne <markap14@hotmail.com>
This commit is contained in:
parent
d4632bdd5d
commit
b1217f529b
@ -45,7 +45,15 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
public @interface Restricted {
|
||||
/**
|
||||
* Provides a description of why the component usage is restricted
|
||||
* Provides a description of why the component usage is restricted. If using granular
|
||||
* restrictions, specific explanations should be set in the Restriction.
|
||||
*/
|
||||
String value();
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* Provides a listing of specific Restrictions. If unspecified, this component will
|
||||
* require access to restricted components regardless of restrictions.
|
||||
*/
|
||||
Restriction[] restrictions() default {};
|
||||
|
||||
}
|
||||
|
@ -14,20 +14,34 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.authorization.resource;
|
||||
package org.apache.nifi.annotation.behavior;
|
||||
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
|
||||
public class RestrictedComponentsAuthorizable implements Authorizable {
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Override
|
||||
public Authorizable getParentAuthorizable() {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Specific restriction for a component. Indicates what the required permission is and why the restriction exists.
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface Restriction {
|
||||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return ResourceFactory.getRestrictedComponentsResource();
|
||||
}
|
||||
/**
|
||||
* Provides a listing of RequiredPermissions.
|
||||
*/
|
||||
RequiredPermission requiredPermission();
|
||||
|
||||
}
|
||||
/**
|
||||
* Provides a explanation of why the component usage is restricted
|
||||
*/
|
||||
String explanation();
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum RequiredPermission {
|
||||
READ_FILESYSTEM("read-filesystem", "read filesystem"),
|
||||
WRITE_FILESYSTEM("write-filesystem", "write filesystem"),
|
||||
EXECUTE_CODE("execute-code", "execute code"),
|
||||
ACCESS_KEYTAB("access-keytab", "access keytab"),
|
||||
EXPORT_NIFI_DETAILS("export-nifi-details", "export nifi details");
|
||||
|
||||
private String permissionIdentifier;
|
||||
private String permissionLabel;
|
||||
|
||||
RequiredPermission(String permissionIdentifier, String permissionLabel) {
|
||||
this.permissionIdentifier = permissionIdentifier;
|
||||
this.permissionLabel = permissionLabel;
|
||||
}
|
||||
|
||||
public String getPermissionIdentifier() {
|
||||
return permissionIdentifier;
|
||||
}
|
||||
|
||||
public String getPermissionLabel() {
|
||||
return permissionLabel;
|
||||
}
|
||||
|
||||
public static RequiredPermission valueOfPermissionIdentifier(final String permissionIdentifier) {
|
||||
return Arrays.stream(RequiredPermission.values())
|
||||
.filter(candidate -> candidate.getPermissionIdentifier().equals(permissionIdentifier))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
}
|
@ -1044,7 +1044,10 @@ Global access policies govern the following system level authorizations:
|
||||
|Data Provenance
|
||||
|
||||
|access restricted components
|
||||
|Allows users to create/modify restricted components assuming otherwise sufficient permissions
|
||||
|Allows users to create/modify restricted components assuming other permissions are sufficient. The restricted
|
||||
components may indicate which specific permissions are required. Permissions can be granted for specific
|
||||
restrictions or be granted regardless of restrictions. If permission is granted regardless of restrictions,
|
||||
the user can create/modify all restricted components.
|
||||
|N/A
|
||||
|
||||
|access all policies
|
||||
|
@ -191,7 +191,9 @@ The available global access policies are:
|
||||
|view the UI |Allows users to view the UI
|
||||
|access the controller |Allows users to view and modify the controller including reporting tasks, Controller Services, and nodes in the cluster
|
||||
|query provenance |Allows users to submit a provenance search and request even lineage
|
||||
|access restricted components |Allows users to create/modify restricted components assuming otherwise sufficient permissions
|
||||
|access restricted components |Allows users to create/modify restricted components assuming other permissions are sufficient. The restricted
|
||||
components may indicate which specific permissions are required. Permissions can be granted for specific restrictions or be granted regardless
|
||||
of restrictions. If permission is granted regardless of restrictions, the user can create/modify all restricted components.
|
||||
|access all policies |Allows users to view and modify the policies for all components
|
||||
|access users/groups |Allows users view and modify the users and user groups
|
||||
|retrieve site-to-site details | Allows other NiFi instances to retrieve Site-To-Site details
|
||||
@ -267,13 +269,18 @@ image::add-processor-with-tag-cloud.png["Add Processor with Tag Cloud"]
|
||||
|
||||
Restricted components will be marked with a
|
||||
image:restricted.png["Restricted"]
|
||||
icon next to their name. These are components that can be used to execute arbitrary unsanitized code provided by the operator
|
||||
through the NiFi REST API/UI or can be used to obtain or alter data on the NiFi host system using the NiFi OS credentials.
|
||||
These components could be used by an otherwise authorized NiFi user to go beyond the intended use of the application, escalate
|
||||
privilege, or could expose data about the internals of the NiFi process or the host system. All of these capabilities should
|
||||
be considered privileged, and admins should be aware of these capabilities and explicitly enable them for a subset of trusted users.
|
||||
icon next to their name. Hovering over the tooltip will display the specific restrictions this component requires. If the component
|
||||
does not list any specific restrictions it will require access to restricted components regardless of restrictions. These are components
|
||||
that can be used to execute arbitrary unsanitized code provided by the operator through the NiFi REST API/UI or can be used to obtain
|
||||
or alter data on the NiFi host system using the NiFi OS credentials. These components could be used by an otherwise authorized NiFi
|
||||
user to go beyond the intended use of the application, escalate privilege, or could expose data about the internals of the NiFi process
|
||||
or the host system. All of these capabilities should be considered privileged, and admins should be aware of these capabilities and
|
||||
explicitly enable them for a subset of trusted users.
|
||||
|
||||
Before a user is allowed to create and modify restricted components they must be granted access to restricted components. For more information refer to
|
||||
Before a user is allowed to create and modify restricted components they must be granted access to restricted components. This can be
|
||||
assigned regardless of restrictions. In this case, the user will have access to all restricted components. Alternatively, users can
|
||||
be assigned access to specific restrictions. If the user has been granted access to all restrictions a component requires, they will
|
||||
have access to that component assuming otherwise sufficient permissions. For more information refer to
|
||||
<<UI-with-multi-tenant-authorization>>.
|
||||
|
||||
Clicking the `Add` button or double-clicking on a Processor Type will add the selected Processor to the canvas at the
|
||||
|
@ -25,12 +25,14 @@ import org.apache.flume.conf.Configurables;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.TriggerSerially;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.Validator;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
@ -49,7 +51,13 @@ import java.util.Set;
|
||||
@Tags({"flume", "hadoop", "put", "sink", "restricted"})
|
||||
@InputRequirement(Requirement.INPUT_REQUIRED)
|
||||
@CapabilityDescription("Execute a Flume sink. Each input FlowFile is converted into a Flume Event for processing by the sink.")
|
||||
@Restricted("Provides operator the ability to execute arbitrary Flume configurations assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary Flume configurations assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ExecuteFlumeSink extends AbstractFlumeProcessor {
|
||||
|
||||
public static final PropertyDescriptor SINK_TYPE = new PropertyDescriptor.Builder()
|
||||
|
@ -29,12 +29,14 @@ import org.apache.flume.source.EventDrivenSourceRunner;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.TriggerSerially;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.Validator;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
@ -55,7 +57,13 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
@Tags({"flume", "hadoop", "get", "source", "restricted"})
|
||||
@InputRequirement(Requirement.INPUT_FORBIDDEN)
|
||||
@CapabilityDescription("Execute a Flume source. Each Flume Event is sent to the success relationship as a FlowFile")
|
||||
@Restricted("Provides operator the ability to execute arbitrary Flume configurations assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary Flume configurations assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ExecuteFlumeSource extends AbstractFlumeProcessor {
|
||||
|
||||
public static final PropertyDescriptor SOURCE_TYPE = new PropertyDescriptor.Builder()
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.web.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class used for providing details about a components usage restriction.
|
||||
*/
|
||||
@XmlType(name = "componentRestrictionPermission")
|
||||
public class ComponentRestrictionPermissionDTO {
|
||||
|
||||
private RequiredPermissionDTO requiredPermission;
|
||||
private PermissionsDTO permissions;
|
||||
|
||||
/**
|
||||
* @return The required permission necessary for this restriction.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The required permission necessary for this restriction."
|
||||
)
|
||||
public RequiredPermissionDTO getRequiredPermission() {
|
||||
return requiredPermission;
|
||||
}
|
||||
|
||||
public void setRequiredPermission(RequiredPermissionDTO requiredPermission) {
|
||||
this.requiredPermission = requiredPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The permissions for this component restriction.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The permissions for this component restriction. Note: the read permission are not used and will always be false."
|
||||
)
|
||||
public PermissionsDTO getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public void setPermissions(PermissionsDTO permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(requiredPermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(requiredPermission, ((ComponentRestrictionPermissionDTO)obj).requiredPermission);
|
||||
}
|
||||
}
|
@ -33,7 +33,9 @@ public class DocumentedTypeDTO {
|
||||
private BundleDTO bundle;
|
||||
private List<ControllerServiceApiDTO> controllerServiceApis;
|
||||
private String description;
|
||||
private boolean restricted;
|
||||
private String usageRestriction;
|
||||
private Set<ExplicitRestrictionDTO> explicitRestrictions;
|
||||
private String deprecationReason;
|
||||
private Set<String> tags;
|
||||
|
||||
@ -51,11 +53,39 @@ public class DocumentedTypeDTO {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this type is restricted
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Whether this type is restricted."
|
||||
)
|
||||
public boolean isRestricted() {
|
||||
return restricted;
|
||||
}
|
||||
|
||||
public void setRestricted(boolean restricted) {
|
||||
this.restricted = restricted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An optional collection of explicit restrictions
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "An optional collection of explicit restrictions. If specified, these explicit restrictions will be enfored."
|
||||
)
|
||||
public Set<ExplicitRestrictionDTO> getExplicitRestrictions() {
|
||||
return explicitRestrictions;
|
||||
}
|
||||
|
||||
public void setExplicitRestrictions(Set<ExplicitRestrictionDTO> explicitRestrictions) {
|
||||
this.explicitRestrictions = explicitRestrictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An optional description of why the usage of this component is restricted
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The description of why the usage of this component is restricted."
|
||||
value = "The optional description of why the usage of this component is restricted."
|
||||
)
|
||||
public String getUsageRestriction() {
|
||||
return usageRestriction;
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.web.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* Class used for providing details about a components usage restriction.
|
||||
*/
|
||||
@XmlType(name = "explicitRestriction")
|
||||
public class ExplicitRestrictionDTO {
|
||||
|
||||
private RequiredPermissionDTO requiredPermission;
|
||||
private String explanation;
|
||||
|
||||
/**
|
||||
* @return The required permission necessary for this restriction.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The required permission necessary for this restriction."
|
||||
)
|
||||
public RequiredPermissionDTO getRequiredPermission() {
|
||||
return requiredPermission;
|
||||
}
|
||||
|
||||
public void setRequiredPermission(RequiredPermissionDTO requiredPermission) {
|
||||
this.requiredPermission = requiredPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The description of why the usage of this component is restricted for this required permission.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The description of why the usage of this component is restricted for this required permission."
|
||||
)
|
||||
public String getExplanation() {
|
||||
return explanation;
|
||||
}
|
||||
|
||||
public void setExplanation(String explanation) {
|
||||
this.explanation = explanation;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.web.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class used for providing details about a components usage restriction.
|
||||
*/
|
||||
@XmlType(name = "requiredPermission")
|
||||
public class RequiredPermissionDTO {
|
||||
|
||||
private String id;
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* @return The required sub-permission necessary for this restriction.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The required sub-permission necessary for this restriction."
|
||||
)
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label for the required sub-permission necessary for this restriction.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The label for the required sub-permission necessary for this restriction."
|
||||
)
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(id, ((RequiredPermissionDTO)obj).id);
|
||||
}
|
||||
}
|
@ -17,9 +17,11 @@
|
||||
package org.apache.nifi.web.api.entity;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.nifi.web.api.dto.ComponentRestrictionPermissionDTO;
|
||||
import org.apache.nifi.web.api.dto.PermissionsDTO;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds the users identity.
|
||||
@ -37,6 +39,7 @@ public class CurrentUserEntity extends Entity {
|
||||
private PermissionsDTO policiesPermissions;
|
||||
private PermissionsDTO systemPermissions;
|
||||
private PermissionsDTO restrictedComponentsPermissions;
|
||||
private Set<ComponentRestrictionPermissionDTO> componentRestrictionPermissions;
|
||||
|
||||
private boolean canVersionFlows;
|
||||
|
||||
@ -148,6 +151,18 @@ public class CurrentUserEntity extends Entity {
|
||||
this.restrictedComponentsPermissions = restrictedComponentsPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return permissions for specific component restrictions
|
||||
*/
|
||||
@ApiModelProperty("Permissions for specific component restrictions.")
|
||||
public Set<ComponentRestrictionPermissionDTO> getComponentRestrictionPermissions() {
|
||||
return componentRestrictionPermissions;
|
||||
}
|
||||
|
||||
public void setComponentRestrictionPermissions(Set<ComponentRestrictionPermissionDTO> componentRestrictionPermissions) {
|
||||
this.componentRestrictionPermissions = componentRestrictionPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the current user can version flows
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@ package org.apache.nifi.documentation.html;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperties;
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
@ -248,7 +249,32 @@ public class HtmlDocumentationWriter implements DocumentationWriter {
|
||||
writeSimpleElement(xmlStreamWriter, "h3", "Restricted: ");
|
||||
|
||||
if(restricted != null) {
|
||||
xmlStreamWriter.writeCharacters(restricted.value());
|
||||
final String value = restricted.value();
|
||||
|
||||
if (!StringUtils.isBlank(value)) {
|
||||
xmlStreamWriter.writeCharacters(restricted.value());
|
||||
}
|
||||
|
||||
final Restriction[] restrictions = restricted.restrictions();
|
||||
if (restrictions != null && restrictions.length > 0) {
|
||||
xmlStreamWriter.writeStartElement("table");
|
||||
xmlStreamWriter.writeAttribute("id", "restrictions");
|
||||
xmlStreamWriter.writeStartElement("tr");
|
||||
writeSimpleElement(xmlStreamWriter, "th", "Required Permission");
|
||||
writeSimpleElement(xmlStreamWriter, "th", "Explanation");
|
||||
xmlStreamWriter.writeEndElement();
|
||||
|
||||
for (Restriction restriction : restrictions) {
|
||||
xmlStreamWriter.writeStartElement("tr");
|
||||
writeSimpleElement(xmlStreamWriter, "td", restriction.requiredPermission().getPermissionLabel());
|
||||
writeSimpleElement(xmlStreamWriter, "td", restriction.explanation());
|
||||
xmlStreamWriter.writeEndElement();
|
||||
}
|
||||
|
||||
xmlStreamWriter.writeEndElement();
|
||||
} else {
|
||||
xmlStreamWriter.writeCharacters("This component requires access to restricted components regardless of restriction.");
|
||||
}
|
||||
} else {
|
||||
xmlStreamWriter.writeCharacters("This component is not restricted.");
|
||||
}
|
||||
|
@ -18,15 +18,16 @@ package org.apache.nifi.documentation.example;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.DynamicRelationship;
|
||||
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
|
||||
import org.apache.nifi.annotation.behavior.SystemResource;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.behavior.SystemResource;
|
||||
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
@ -34,6 +35,7 @@ import org.apache.nifi.annotation.lifecycle.OnRemoved;
|
||||
import org.apache.nifi.annotation.lifecycle.OnShutdown;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.processor.AbstractProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
@ -59,7 +61,14 @@ import java.util.Set;
|
||||
@DynamicProperty(name = "Relationship Name", supportsExpressionLanguage = true, value = "some XPath", description = "Routes FlowFiles to relationships based on XPath")
|
||||
@DynamicRelationship(name = "name from dynamic property", description = "all files that match the properties XPath")
|
||||
@Stateful(scopes = {Scope.CLUSTER, Scope.LOCAL}, description = "state management description")
|
||||
@Restricted("processor restriction description")
|
||||
@Restricted(
|
||||
value = "processor restriction description",
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Requires read filesystem permission")
|
||||
}
|
||||
)
|
||||
@InputRequirement(Requirement.INPUT_FORBIDDEN)
|
||||
@SystemResourceConsideration(resource = SystemResource.CPU)
|
||||
@SystemResourceConsideration(resource = SystemResource.DISK, description = "Customized disk usage description")
|
||||
|
@ -19,6 +19,7 @@ package org.apache.nifi.documentation.html;
|
||||
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
|
||||
import org.apache.nifi.annotation.behavior.SystemResource;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.documentation.DocumentationWriter;
|
||||
import org.apache.nifi.documentation.example.DeprecatedProcessor;
|
||||
import org.apache.nifi.documentation.example.FullyDocumentedProcessor;
|
||||
@ -73,6 +74,8 @@ public class ProcessorDocumentationWriterTest {
|
||||
assertContains(results, "state management description");
|
||||
|
||||
assertContains(results, "processor restriction description");
|
||||
assertContains(results, RequiredPermission.READ_FILESYSTEM.getPermissionLabel());
|
||||
assertContains(results, "Requires read filesystem permission");
|
||||
|
||||
assertNotContains(results, "iconSecure.png");
|
||||
assertContains(results, FullyDocumentedProcessor.class.getAnnotation(CapabilityDescription.class)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.apache.nifi.authorization.resource;
|
||||
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -327,6 +328,31 @@ public final class ResourceFactory {
|
||||
return RESTRICTED_COMPONENTS_RESOURCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Resource for accessing certain kinds of restricted components.
|
||||
*
|
||||
* @param requiredPermission The required permission
|
||||
* @return The restricted components resource
|
||||
*/
|
||||
public static Resource getRestrictedComponentsResource(final RequiredPermission requiredPermission) {
|
||||
return new Resource() {
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return String.format("%s/%s", RESTRICTED_COMPONENTS_RESOURCE.getIdentifier(), requiredPermission.getPermissionIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return requiredPermission.getPermissionLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSafeDescription() {
|
||||
return "Components requiring additional permission: " + requiredPermission.getPermissionLabel();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Resource for accessing Tenants which includes creating, modifying, and deleting Users and UserGroups.
|
||||
*
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.authorization.AccessDeniedException;
|
||||
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.components.RequiredPermission;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class RestrictedComponentsAuthorizableFactory {
|
||||
|
||||
private static final Authorizable RESTRICTED_COMPONENTS_AUTHORIZABLE = new Authorizable() {
|
||||
@Override
|
||||
public Authorizable getParentAuthorizable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return ResourceFactory.getRestrictedComponentsResource();
|
||||
}
|
||||
};
|
||||
|
||||
public static Authorizable getRestrictedComponentsAuthorizable() {
|
||||
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
||||
}
|
||||
|
||||
public static Authorizable getRestrictedComponentsAuthorizable(final RequiredPermission requiredPermission) {
|
||||
return new Authorizable() {
|
||||
@Override
|
||||
public Authorizable getParentAuthorizable() {
|
||||
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource() {
|
||||
return ResourceFactory.getRestrictedComponentsResource(requiredPermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user, Map<String, String> resourceContext) {
|
||||
if (user == null) {
|
||||
throw new AccessDeniedException("Unknown user.");
|
||||
}
|
||||
|
||||
final AuthorizationResult resourceResult = Authorizable.super.checkAuthorization(authorizer, action, user, resourceContext);
|
||||
|
||||
// if we're denied from the resource try inheriting
|
||||
if (Result.Denied.equals(resourceResult.getResult())) {
|
||||
return getParentAuthorizable().checkAuthorization(authorizer, action, user, resourceContext);
|
||||
} else {
|
||||
return resourceResult;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorize(Authorizer authorizer, RequestAction action, NiFiUser user, Map<String, String> resourceContext) throws AccessDeniedException {
|
||||
if (user == null) {
|
||||
throw new AccessDeniedException("Unknown user.");
|
||||
}
|
||||
|
||||
try {
|
||||
Authorizable.super.authorize(authorizer, action, user, resourceContext);
|
||||
} catch (final AccessDeniedException resourceDenied) {
|
||||
// if we're denied from the resource try inheriting
|
||||
try {
|
||||
getParentAuthorizable().authorize(authorizer, action, user, resourceContext);
|
||||
} catch (final AccessDeniedException policiesDenied) {
|
||||
throw resourceDenied;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Set<Authorizable> getRestrictedComponentsAuthorizable(final Class<?> configurableComponentClass) {
|
||||
final Set<Authorizable> authorizables = new HashSet<>();
|
||||
|
||||
final Restricted restricted = configurableComponentClass.getAnnotation(Restricted.class);
|
||||
|
||||
if (restricted != null) {
|
||||
final Restriction[] restrictions = restricted.restrictions();
|
||||
|
||||
if (restrictions != null && restrictions.length > 0) {
|
||||
Arrays.stream(restrictions).forEach(restriction -> authorizables.add(getRestrictedComponentsAuthorizable(restriction.requiredPermission())));
|
||||
} else {
|
||||
authorizables.add(getRestrictedComponentsAuthorizable());
|
||||
}
|
||||
}
|
||||
|
||||
return authorizables;
|
||||
}
|
||||
|
||||
}
|
@ -19,6 +19,7 @@ package org.apache.nifi.cluster.coordination.http.endpoints;
|
||||
|
||||
import org.apache.nifi.cluster.manager.NodeResponse;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.web.api.dto.ComponentRestrictionPermissionDTO;
|
||||
import org.apache.nifi.web.api.dto.PermissionsDTO;
|
||||
import org.apache.nifi.web.api.entity.CurrentUserEntity;
|
||||
|
||||
@ -53,6 +54,23 @@ public class CurrentUserEndpointMerger extends AbstractSingleEntityEndpoint<Curr
|
||||
mergePermissions(clientEntity.getPoliciesPermissions(), entity.getPoliciesPermissions());
|
||||
mergePermissions(clientEntity.getProvenancePermissions(), entity.getProvenancePermissions());
|
||||
mergePermissions(clientEntity.getTenantsPermissions(), entity.getTenantsPermissions());
|
||||
mergePermissions(clientEntity.getSystemPermissions(), entity.getSystemPermissions());
|
||||
mergePermissions(clientEntity.getTenantsPermissions(), entity.getTenantsPermissions());
|
||||
|
||||
final Set<ComponentRestrictionPermissionDTO> clientEntityComponentRestrictionsPermissions = clientEntity.getComponentRestrictionPermissions();
|
||||
final Set<ComponentRestrictionPermissionDTO> entityComponentRestrictionsPermissions = entity.getComponentRestrictionPermissions();
|
||||
|
||||
// only retain the component restriction permissions in common
|
||||
clientEntityComponentRestrictionsPermissions.retainAll(entityComponentRestrictionsPermissions);
|
||||
|
||||
// merge the component restriction permissions
|
||||
clientEntityComponentRestrictionsPermissions.forEach(clientEntityPermission -> {
|
||||
final ComponentRestrictionPermissionDTO entityPermission = entityComponentRestrictionsPermissions.stream().filter(entityComponentRestrictionsPermission -> {
|
||||
return entityComponentRestrictionsPermission.getRequiredPermission().getId().equals(clientEntityPermission.getRequiredPermission().getId());
|
||||
}).findFirst().orElse(null);
|
||||
|
||||
mergePermissions(clientEntityPermission.getPermissions(), entityPermission.getPermissions());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.cluster.coordination.http.endpoints;
|
||||
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.web.api.dto.ComponentRestrictionPermissionDTO;
|
||||
import org.apache.nifi.web.api.dto.PermissionsDTO;
|
||||
import org.apache.nifi.web.api.dto.RequiredPermissionDTO;
|
||||
import org.apache.nifi.web.api.entity.CurrentUserEntity;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class CurrentUserEndpointMergerTest {
|
||||
|
||||
@Test
|
||||
public void testMergeUserPermissions() {
|
||||
final NodeIdentifier nodeId1 = new NodeIdentifier("1", "localhost", 9000, "localhost", 9001, "localhost", 9002, 9003, false);
|
||||
final CurrentUserEntity userNode1 = new CurrentUserEntity();
|
||||
userNode1.setControllerPermissions(buildPermissions(true, false));
|
||||
userNode1.setCountersPermissions(buildPermissions(true, true));
|
||||
userNode1.setPoliciesPermissions(buildPermissions(true, true));
|
||||
userNode1.setProvenancePermissions(buildPermissions(false, false));
|
||||
userNode1.setRestrictedComponentsPermissions(buildPermissions(false, false));
|
||||
userNode1.setSystemPermissions(buildPermissions(true, true));
|
||||
userNode1.setTenantsPermissions(buildPermissions(false, true));
|
||||
|
||||
final Set<ComponentRestrictionPermissionDTO> componentRestrictionsNode1 = new HashSet<>();
|
||||
componentRestrictionsNode1.add(buildComponentRestriction(RequiredPermission.ACCESS_KEYTAB, true, true));
|
||||
componentRestrictionsNode1.add(buildComponentRestriction(RequiredPermission.WRITE_FILESYSTEM, false, true));
|
||||
componentRestrictionsNode1.add(buildComponentRestriction(RequiredPermission.READ_FILESYSTEM, true, true));
|
||||
userNode1.setComponentRestrictionPermissions(componentRestrictionsNode1);
|
||||
|
||||
final NodeIdentifier nodeId2 = new NodeIdentifier("2", "localhost", 8000, "localhost", 8001, "localhost", 8002, 8003, false);
|
||||
final CurrentUserEntity userNode2 = new CurrentUserEntity();
|
||||
userNode2.setControllerPermissions(buildPermissions(false, true));
|
||||
userNode2.setCountersPermissions(buildPermissions(true, false));
|
||||
userNode2.setPoliciesPermissions(buildPermissions(true, true));
|
||||
userNode2.setProvenancePermissions(buildPermissions(false, false));
|
||||
userNode2.setRestrictedComponentsPermissions(buildPermissions(true, true));
|
||||
userNode2.setSystemPermissions(buildPermissions(false, false));
|
||||
userNode2.setTenantsPermissions(buildPermissions(true, true));
|
||||
|
||||
final Set<ComponentRestrictionPermissionDTO> componentRestrictionsNode2 = new HashSet<>();
|
||||
componentRestrictionsNode2.add(buildComponentRestriction(RequiredPermission.ACCESS_KEYTAB, true, false));
|
||||
componentRestrictionsNode2.add(buildComponentRestriction(RequiredPermission.WRITE_FILESYSTEM, true, false));
|
||||
componentRestrictionsNode2.add(buildComponentRestriction(RequiredPermission.EXECUTE_CODE, true, true));
|
||||
userNode2.setComponentRestrictionPermissions(componentRestrictionsNode2);
|
||||
|
||||
final Map<NodeIdentifier, CurrentUserEntity> entityMap = new HashMap<>();
|
||||
entityMap.put(nodeId1, userNode1);
|
||||
entityMap.put(nodeId2, userNode2);
|
||||
|
||||
final CurrentUserEndpointMerger merger = new CurrentUserEndpointMerger();
|
||||
merger.mergeResponses(userNode1, entityMap, Collections.emptySet(), Collections.emptySet());
|
||||
|
||||
assertFalse(userNode1.getControllerPermissions().getCanRead());
|
||||
assertFalse(userNode1.getControllerPermissions().getCanWrite());
|
||||
assertTrue(userNode1.getCountersPermissions().getCanRead());
|
||||
assertFalse(userNode1.getCountersPermissions().getCanWrite());
|
||||
assertTrue(userNode1.getPoliciesPermissions().getCanRead());
|
||||
assertTrue(userNode1.getPoliciesPermissions().getCanWrite());
|
||||
assertFalse(userNode1.getProvenancePermissions().getCanRead());
|
||||
assertFalse(userNode1.getProvenancePermissions().getCanWrite());
|
||||
assertFalse(userNode1.getRestrictedComponentsPermissions().getCanRead());
|
||||
assertFalse(userNode1.getRestrictedComponentsPermissions().getCanWrite());
|
||||
assertFalse(userNode1.getSystemPermissions().getCanRead());
|
||||
assertFalse(userNode1.getSystemPermissions().getCanWrite());
|
||||
assertFalse(userNode1.getTenantsPermissions().getCanRead());
|
||||
assertTrue(userNode1.getTenantsPermissions().getCanWrite());
|
||||
|
||||
userNode1.getComponentRestrictionPermissions().forEach(componentRestriction -> {
|
||||
if (RequiredPermission.ACCESS_KEYTAB.getPermissionIdentifier().equals(componentRestriction.getRequiredPermission().getId())) {
|
||||
assertTrue(componentRestriction.getPermissions().getCanRead());
|
||||
assertFalse(componentRestriction.getPermissions().getCanWrite());
|
||||
} else if (RequiredPermission.WRITE_FILESYSTEM.getPermissionIdentifier().equals(componentRestriction.getRequiredPermission().getId())) {
|
||||
assertFalse(componentRestriction.getPermissions().getCanRead());
|
||||
assertFalse(componentRestriction.getPermissions().getCanWrite());
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private PermissionsDTO buildPermissions(final boolean canRead, final boolean canWrite) {
|
||||
final PermissionsDTO permissionsDto = new PermissionsDTO();
|
||||
permissionsDto.setCanRead(canRead);
|
||||
permissionsDto.setCanWrite(canWrite);
|
||||
return permissionsDto;
|
||||
}
|
||||
|
||||
private ComponentRestrictionPermissionDTO buildComponentRestriction(final RequiredPermission requiredPermission, final boolean canRead, final boolean canWrite) {
|
||||
final RequiredPermissionDTO requiredPermissionDto = new RequiredPermissionDTO();
|
||||
requiredPermissionDto.setId(requiredPermission.getPermissionIdentifier());
|
||||
requiredPermissionDto.setLabel(requiredPermission.getPermissionLabel());
|
||||
|
||||
final ComponentRestrictionPermissionDTO componentRestrictionPermissionDto = new ComponentRestrictionPermissionDTO();
|
||||
componentRestrictionPermissionDto.setRequiredPermission(requiredPermissionDto);
|
||||
componentRestrictionPermissionDto.setPermissions(buildPermissions(canRead, canWrite));
|
||||
return componentRestrictionPermissionDto;
|
||||
}
|
||||
}
|
@ -21,8 +21,9 @@ 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.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ComponentAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.RestrictedComponentsAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.RestrictedComponentsAuthorizableFactory;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
@ -90,13 +91,18 @@ public interface ConfiguredComponent extends ComponentAuthorizable {
|
||||
*/
|
||||
String getComponentType();
|
||||
|
||||
/**
|
||||
* @return the class of the underlying
|
||||
*/
|
||||
Class<?> getComponentClass();
|
||||
|
||||
/**
|
||||
* @return the Canonical Class Name of the component
|
||||
*/
|
||||
String getCanonicalClassName();
|
||||
|
||||
/**
|
||||
* @return whether or not the underlying implementation is restricted
|
||||
* @return whether or not the underlying implementation has any restrictions
|
||||
*/
|
||||
boolean isRestricted();
|
||||
|
||||
@ -115,10 +121,13 @@ public interface ConfiguredComponent extends ComponentAuthorizable {
|
||||
// if this is a modification request and the reporting task is restricted ensure the user has elevated privileges. if this
|
||||
// is not a modification request, we just want to use the normal rules
|
||||
if (RequestAction.WRITE.equals(action) && isRestricted()) {
|
||||
final RestrictedComponentsAuthorizable restrictedComponentsAuthorizable = new RestrictedComponentsAuthorizable();
|
||||
final AuthorizationResult result = restrictedComponentsAuthorizable.checkAuthorization(authorizer, RequestAction.WRITE, user, resourceContext);
|
||||
if (Result.Denied.equals(result.getResult())) {
|
||||
return result;
|
||||
final Set<Authorizable> restrictedComponentsAuthorizables = RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(getComponentClass());
|
||||
|
||||
for (final Authorizable restrictedComponentsAuthorizable : restrictedComponentsAuthorizables) {
|
||||
final AuthorizationResult result = restrictedComponentsAuthorizable.checkAuthorization(authorizer, RequestAction.WRITE, user, resourceContext);
|
||||
if (Result.Denied.equals(result.getResult())) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,8 +140,11 @@ public interface ConfiguredComponent extends ComponentAuthorizable {
|
||||
// if this is a modification request and the reporting task is restricted ensure the user has elevated privileges. if this
|
||||
// is not a modification request, we just want to use the normal rules
|
||||
if (RequestAction.WRITE.equals(action) && isRestricted()) {
|
||||
final RestrictedComponentsAuthorizable restrictedComponentsAuthorizable = new RestrictedComponentsAuthorizable();
|
||||
restrictedComponentsAuthorizable.authorize(authorizer, RequestAction.WRITE, user, resourceContext);
|
||||
final Set<Authorizable> restrictedComponentsAuthorizables = RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(getComponentClass());
|
||||
|
||||
for (final Authorizable restrictedComponentsAuthorizable : restrictedComponentsAuthorizables) {
|
||||
restrictedComponentsAuthorizable.authorize(authorizer, RequestAction.WRITE, user, resourceContext);
|
||||
}
|
||||
}
|
||||
|
||||
// defer to the base authorization check
|
||||
|
@ -244,6 +244,11 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
||||
return getProcessor().getClass().isAnnotationPresent(Restricted.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getComponentClass() {
|
||||
return getProcessor().getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
return getProcessor().getClass().isAnnotationPresent(DeprecationNotice.class);
|
||||
|
@ -67,6 +67,11 @@ public class StandardReportingTaskNode extends AbstractReportingTaskNode impleme
|
||||
return getReportingTask().getClass().isAnnotationPresent(Restricted.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getComponentClass() {
|
||||
return getReportingContext().getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
return getReportingTask().getClass().isAnnotationPresent(DeprecationNotice.class);
|
||||
|
@ -150,6 +150,11 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
||||
return getControllerServiceImplementation().getClass().isAnnotationPresent(Restricted.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getComponentClass() {
|
||||
return getControllerServiceImplementation().getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
return getControllerServiceImplementation().getClass().isAnnotationPresent(DeprecationNotice.class);
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.apache.nifi.authorization;
|
||||
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.web.api.dto.BundleDTO;
|
||||
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||
|
||||
@ -263,4 +264,12 @@ public interface AuthorizableLookup {
|
||||
* @return authorizable
|
||||
*/
|
||||
Authorizable getRestrictedComponents();
|
||||
|
||||
/**
|
||||
* Get the authorizable for accessing restricted components with a specific required permission.
|
||||
*
|
||||
* @param requiredPermission required permission
|
||||
* @return authorizable
|
||||
*/
|
||||
Authorizable getRestrictedComponents(RequiredPermission requiredPermission);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Authorizable for a component that references a ControllerService.
|
||||
@ -39,6 +40,13 @@ public interface ComponentAuthorizable {
|
||||
*/
|
||||
boolean isRestricted();
|
||||
|
||||
/**
|
||||
* Returns all component restriction authorizables for this component.
|
||||
*
|
||||
* @return all component restriction authorizables
|
||||
*/
|
||||
Set<Authorizable> getRestrictedAuthorizables();
|
||||
|
||||
/**
|
||||
* Returns the property descriptor for the specified property.
|
||||
*
|
||||
|
@ -24,12 +24,13 @@ import org.apache.nifi.authorization.resource.DataAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.DataTransferAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.authorization.resource.ResourceType;
|
||||
import org.apache.nifi.authorization.resource.RestrictedComponentsAuthorizable;
|
||||
import org.apache.nifi.authorization.resource.RestrictedComponentsAuthorizableFactory;
|
||||
import org.apache.nifi.authorization.resource.TenantAuthorizable;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.connectable.Connection;
|
||||
import org.apache.nifi.connectable.Port;
|
||||
@ -70,7 +71,6 @@ import java.util.stream.Collectors;
|
||||
class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
|
||||
private static final TenantAuthorizable TENANT_AUTHORIZABLE = new TenantAuthorizable();
|
||||
private static final Authorizable RESTRICTED_COMPONENTS_AUTHORIZABLE = new RestrictedComponentsAuthorizable();
|
||||
|
||||
private static final Authorizable POLICIES_AUTHORIZABLE = new Authorizable() {
|
||||
@Override
|
||||
@ -500,6 +500,20 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
} else {
|
||||
return new DataTransferAuthorizable(getAccessPolicy(resourceType, resource));
|
||||
}
|
||||
} else if (ResourceType.RestrictedComponents.equals(resourceType)) {
|
||||
final String slashRequiredPermission = StringUtils.substringAfter(resource, resourceType.getValue());
|
||||
|
||||
if (slashRequiredPermission.startsWith("/")) {
|
||||
final RequiredPermission requiredPermission = RequiredPermission.valueOfPermissionIdentifier(slashRequiredPermission.substring(1));
|
||||
|
||||
if (requiredPermission == null) {
|
||||
throw new ResourceNotFoundException("Unrecognized resource: " + resource);
|
||||
}
|
||||
|
||||
return getRestrictedComponents(requiredPermission);
|
||||
} else {
|
||||
return getRestrictedComponents();
|
||||
}
|
||||
} else {
|
||||
return getAccessPolicy(resourceType, resource);
|
||||
}
|
||||
@ -629,9 +643,6 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
case Tenant:
|
||||
authorizable = getTenant();
|
||||
break;
|
||||
case RestrictedComponents:
|
||||
authorizable = getRestrictedComponents();
|
||||
break;
|
||||
}
|
||||
|
||||
if (authorizable == null) {
|
||||
@ -724,7 +735,12 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
|
||||
@Override
|
||||
public Authorizable getRestrictedComponents() {
|
||||
return RESTRICTED_COMPONENTS_AUTHORIZABLE;
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getRestrictedComponents(final RequiredPermission requiredPermission) {
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(requiredPermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -753,6 +769,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
return configurableComponent.getClass().isAnnotationPresent(Restricted.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getRestrictedAuthorizables() {
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(configurableComponent.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||
return null;
|
||||
@ -794,6 +815,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
return processorNode.isRestricted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getRestrictedAuthorizables() {
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(processorNode.getComponentClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||
return processorNode.getProperty(propertyDescriptor);
|
||||
@ -835,6 +861,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
return controllerServiceNode.isRestricted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getRestrictedAuthorizables() {
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(controllerServiceNode.getComponentClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||
return controllerServiceNode.getProperty(propertyDescriptor);
|
||||
@ -876,6 +907,11 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
|
||||
return reportingTaskNode.isRestricted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authorizable> getRestrictedAuthorizables() {
|
||||
return RestrictedComponentsAuthorizableFactory.getRestrictedComponentsAuthorizable(reportingTaskNode.getComponentClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(PropertyDescriptor propertyDescriptor) {
|
||||
return reportingTaskNode.getProperty(propertyDescriptor);
|
||||
|
@ -55,6 +55,7 @@ import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.Validator;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
@ -136,6 +137,7 @@ import org.apache.nifi.web.api.dto.ComponentDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentDifferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentHistoryDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentReferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentRestrictionPermissionDTO;
|
||||
import org.apache.nifi.web.api.dto.ComponentStateDTO;
|
||||
import org.apache.nifi.web.api.dto.ConnectionDTO;
|
||||
import org.apache.nifi.web.api.dto.ControllerConfigurationDTO;
|
||||
@ -168,6 +170,7 @@ import org.apache.nifi.web.api.dto.RegistryDTO;
|
||||
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
|
||||
import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
|
||||
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
|
||||
import org.apache.nifi.web.api.dto.RequiredPermissionDTO;
|
||||
import org.apache.nifi.web.api.dto.ResourceDTO;
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
import org.apache.nifi.web.api.dto.SnippetDTO;
|
||||
@ -3506,9 +3509,26 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
entity.setControllerPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getController()));
|
||||
entity.setPoliciesPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getPolicies()));
|
||||
entity.setSystemPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getSystem()));
|
||||
entity.setRestrictedComponentsPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getRestrictedComponents()));
|
||||
entity.setCanVersionFlows(CollectionUtils.isNotEmpty(flowRegistryClient.getRegistryIdentifiers()));
|
||||
|
||||
entity.setRestrictedComponentsPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getRestrictedComponents()));
|
||||
|
||||
final Set<ComponentRestrictionPermissionDTO> componentRestrictionPermissions = new HashSet<>();
|
||||
Arrays.stream(RequiredPermission.values()).forEach(requiredPermission -> {
|
||||
final PermissionsDTO restrictionPermissions = dtoFactory.createPermissionsDto(authorizableLookup.getRestrictedComponents(requiredPermission));
|
||||
|
||||
final RequiredPermissionDTO requiredPermissionDto = new RequiredPermissionDTO();
|
||||
requiredPermissionDto.setId(requiredPermission.getPermissionIdentifier());
|
||||
requiredPermissionDto.setLabel(requiredPermission.getPermissionLabel());
|
||||
|
||||
final ComponentRestrictionPermissionDTO componentRestrictionPermissionDto = new ComponentRestrictionPermissionDTO();
|
||||
componentRestrictionPermissionDto.setRequiredPermission(requiredPermissionDto);
|
||||
componentRestrictionPermissionDto.setPermissions(restrictionPermissions);
|
||||
|
||||
componentRestrictionPermissions.add(componentRestrictionPermissionDto);
|
||||
});
|
||||
entity.setComponentRestrictionPermissions(componentRestrictionPermissions);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import org.apache.nifi.authorization.AuthorizableLookup;
|
||||
import org.apache.nifi.authorization.AuthorizeAccess;
|
||||
import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.ComponentAuthorizable;
|
||||
import org.apache.nifi.authorization.ProcessGroupAuthorizable;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.SnippetAuthorizable;
|
||||
@ -447,6 +448,16 @@ public abstract class ApplicationResource {
|
||||
return getRevision(entity.getRevision(), componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize any restrictions for the specified ComponentAuthorizable.
|
||||
*
|
||||
* @param authorizer authorizer
|
||||
* @param authorizable component authorizable
|
||||
*/
|
||||
protected void authorizeRestrictions(final Authorizer authorizer, final ComponentAuthorizable authorizable) {
|
||||
authorizable.getRestrictedAuthorizables().forEach(restrictionAuthorizable -> restrictionAuthorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorizes the specified process group.
|
||||
*
|
||||
|
@ -46,8 +46,8 @@ import org.apache.nifi.web.api.entity.ControllerServiceEntity;
|
||||
import org.apache.nifi.web.api.entity.Entity;
|
||||
import org.apache.nifi.web.api.entity.HistoryEntity;
|
||||
import org.apache.nifi.web.api.entity.NodeEntity;
|
||||
import org.apache.nifi.web.api.entity.RegistryClientsEntity;
|
||||
import org.apache.nifi.web.api.entity.RegistryClientEntity;
|
||||
import org.apache.nifi.web.api.entity.RegistryClientsEntity;
|
||||
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
|
||||
import org.apache.nifi.web.api.request.ClientIdParameter;
|
||||
import org.apache.nifi.web.api.request.DateTimeParameter;
|
||||
@ -277,7 +277,7 @@ public class ControllerResource extends ApplicationResource {
|
||||
authorizable = lookup.getConfigurableComponent(requestReportingTask.getType(), requestReportingTask.getBundle());
|
||||
|
||||
if (authorizable.isRestricted()) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
|
||||
if (requestReportingTask.getProperties() != null) {
|
||||
@ -775,7 +775,7 @@ public class ControllerResource extends ApplicationResource {
|
||||
authorizable = lookup.getConfigurableComponent(requestControllerService.getType(), requestControllerService.getBundle());
|
||||
|
||||
if (authorizable.isRestricted()) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
|
||||
if (requestControllerService.getProperties() != null) {
|
||||
|
@ -159,7 +159,6 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@ -1894,7 +1893,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||
authorizable = lookup.getConfigurableComponent(requestProcessor.getType(), requestProcessor.getBundle());
|
||||
|
||||
if (authorizable.isRestricted()) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
|
||||
final ProcessorConfigDTO config = requestProcessor.getConfig();
|
||||
@ -3037,11 +3036,9 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
final SnippetAuthorizable snippet = authorizeSnippetUsage(lookup, groupId, requestCopySnippetEntity.getSnippetId(), false);
|
||||
|
||||
// flag to only perform the restricted check once, atomic reference so we can mark final and use in lambda
|
||||
final AtomicBoolean restrictedCheckPerformed = new AtomicBoolean(false);
|
||||
final Consumer<ComponentAuthorizable> authorizeRestricted = authorizable -> {
|
||||
if (authorizable.isRestricted() && restrictedCheckPerformed.compareAndSet(false, true)) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
if (authorizable.isRestricted()) {
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3213,11 +3210,9 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||
// ensure read on the template
|
||||
final TemplateContentsAuthorizable templateContents = lookup.getTemplateContents(requestInstantiateTemplateRequestEntity.getSnippet());
|
||||
|
||||
// flag to only perform the restricted check once, atomic reference so we can mark final and use in lambda
|
||||
final AtomicBoolean restrictedCheckPerformed = new AtomicBoolean(false);
|
||||
final Consumer<ComponentAuthorizable> authorizeRestricted = authorizable -> {
|
||||
if (authorizable.isRestricted() && restrictedCheckPerformed.compareAndSet(false, true)) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
if (authorizable.isRestricted()) {
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3595,7 +3590,7 @@ public class ProcessGroupResource extends ApplicationResource {
|
||||
authorizable = lookup.getConfigurableComponent(requestControllerService.getType(), requestControllerService.getBundle());
|
||||
|
||||
if (authorizable.isRestricted()) {
|
||||
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user);
|
||||
authorizeRestrictions(authorizer, authorizable);
|
||||
}
|
||||
|
||||
if (requestControllerService.getProperties() != null) {
|
||||
|
@ -34,6 +34,7 @@ import org.apache.nifi.action.details.FlowChangePurgeDetails;
|
||||
import org.apache.nifi.action.details.MoveDetails;
|
||||
import org.apache.nifi.action.details.PurgeDetails;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.DeprecationNotice;
|
||||
@ -2408,9 +2409,47 @@ public final class DtoFactory {
|
||||
return dto;
|
||||
}
|
||||
|
||||
private boolean isRestricted(final Class<?> cls) {
|
||||
return cls.isAnnotationPresent(Restricted.class);
|
||||
}
|
||||
|
||||
private String getUsageRestriction(final Class<?> cls) {
|
||||
final Restricted restriction = cls.getAnnotation(Restricted.class);
|
||||
return restriction == null ? null : restriction.value();
|
||||
final Restricted restricted = cls.getAnnotation(Restricted.class);
|
||||
|
||||
if (restricted == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(restricted.value())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return restricted.value();
|
||||
}
|
||||
|
||||
private Set<ExplicitRestrictionDTO> getExplicitRestrictions(final Class<?> cls) {
|
||||
final Restricted restricted = cls.getAnnotation(Restricted.class);
|
||||
|
||||
if (restricted == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Restriction[] restrictions = restricted.restrictions();
|
||||
|
||||
if (restrictions == null || restrictions.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Arrays.stream(restrictions).map(restriction -> {
|
||||
final RequiredPermissionDTO requiredPermission = new RequiredPermissionDTO();
|
||||
requiredPermission.setId(restriction.requiredPermission().getPermissionIdentifier());
|
||||
requiredPermission.setLabel(restriction.requiredPermission().getPermissionLabel());
|
||||
|
||||
final ExplicitRestrictionDTO usageRestriction = new ExplicitRestrictionDTO();
|
||||
usageRestriction.setRequiredPermission(requiredPermission);
|
||||
usageRestriction.setExplanation(restriction.explanation());
|
||||
return usageRestriction;
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private String getDeprecationReason(final Class<?> cls) {
|
||||
@ -2649,7 +2688,9 @@ public final class DtoFactory {
|
||||
dto.setBundle(createBundleDto(coordinate));
|
||||
dto.setControllerServiceApis(createControllerServiceApiDto(cls));
|
||||
dto.setDescription(getCapabilityDescription(cls));
|
||||
dto.setRestricted(isRestricted(cls));
|
||||
dto.setUsageRestriction(getUsageRestriction(cls));
|
||||
dto.setExplicitRestrictions(getExplicitRestrictions(cls));
|
||||
dto.setDeprecationReason(getDeprecationReason(cls));
|
||||
dto.setTags(getTags(cls));
|
||||
types.add(dto);
|
||||
|
@ -33,6 +33,7 @@ import org.apache.nifi.bundle.Bundle;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.connectable.Connection;
|
||||
import org.apache.nifi.connectable.Port;
|
||||
@ -110,6 +111,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@ -808,7 +810,6 @@ public class ControllerFacade implements Authorizable {
|
||||
final List<Resource> resources = new ArrayList<>();
|
||||
resources.add(ResourceFactory.getFlowResource());
|
||||
resources.add(ResourceFactory.getSystemResource());
|
||||
resources.add(ResourceFactory.getRestrictedComponentsResource());
|
||||
resources.add(ResourceFactory.getControllerResource());
|
||||
resources.add(ResourceFactory.getCountersResource());
|
||||
resources.add(ResourceFactory.getProvenanceResource());
|
||||
@ -818,6 +819,10 @@ public class ControllerFacade implements Authorizable {
|
||||
resources.add(ResourceFactory.getResourceResource());
|
||||
resources.add(ResourceFactory.getSiteToSiteResource());
|
||||
|
||||
// restricted components
|
||||
resources.add(ResourceFactory.getRestrictedComponentsResource());
|
||||
Arrays.stream(RequiredPermission.values()).forEach(requiredPermission -> resources.add(ResourceFactory.getRestrictedComponentsResource(requiredPermission)));
|
||||
|
||||
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
|
||||
|
||||
// include the root group
|
||||
|
@ -46,6 +46,7 @@ public class AccessControlHelper {
|
||||
private NiFiTestUser readWriteUser;
|
||||
private NiFiTestUser noneUser;
|
||||
private NiFiTestUser privilegedUser;
|
||||
private NiFiTestUser executeCodeUser;
|
||||
|
||||
private static final String CONTEXT_PATH = "/nifi-api";
|
||||
|
||||
@ -83,6 +84,7 @@ public class AccessControlHelper {
|
||||
readWriteUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.READ_WRITE_USER_DN);
|
||||
noneUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.NONE_USER_DN);
|
||||
privilegedUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.PRIVILEGED_USER_DN);
|
||||
executeCodeUser = new NiFiTestUser(server.getClient(), NiFiTestAuthorizer.EXECUTED_CODE_USER_DN);
|
||||
|
||||
// populate the initial data flow
|
||||
NiFiWebApiTest.populateFlow(server.getClient(), baseUrl, readWriteUser, READ_WRITE_CLIENT_ID);
|
||||
@ -108,6 +110,10 @@ public class AccessControlHelper {
|
||||
return privilegedUser;
|
||||
}
|
||||
|
||||
public NiFiTestUser getExecuteCodeUser() {
|
||||
return executeCodeUser;
|
||||
}
|
||||
|
||||
public void testGenericGetUri(final String uri) throws Exception {
|
||||
Response response;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.apache.nifi.integration.accesscontrol;
|
||||
|
||||
import org.apache.nifi.integration.util.ExecuteCodeRestrictedProcessor;
|
||||
import org.apache.nifi.integration.util.NiFiTestAuthorizer;
|
||||
import org.apache.nifi.integration.util.NiFiTestUser;
|
||||
import org.apache.nifi.integration.util.RestrictedProcessor;
|
||||
@ -439,6 +440,12 @@ public class ITProcessorAccessControl {
|
||||
// ensure the request is successful
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// perform the request as a user with read/write and only execute code restricted access
|
||||
response = helper.getExecuteCodeUser().testPost(url, entity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// perform the request as a user with read/write and restricted access
|
||||
response = helper.getPrivilegedUser().testPost(url, entity);
|
||||
|
||||
@ -448,7 +455,54 @@ public class ITProcessorAccessControl {
|
||||
final ProcessorEntity responseEntity = response.readEntity(ProcessorEntity.class);
|
||||
|
||||
// remove the restricted component
|
||||
deleteRestrictedComponent(responseEntity);
|
||||
deleteRestrictedComponent(responseEntity, helper.getPrivilegedUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests attempt to create a restricted processor requiring execute code permissions.
|
||||
*
|
||||
* @throws Exception if there is an error creating this processor
|
||||
*/
|
||||
@Test
|
||||
public void testCreateExecuteCodeRestrictedProcessor() throws Exception {
|
||||
createExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
|
||||
createExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
|
||||
}
|
||||
|
||||
private void createExecuteCodeRestrictedProcessor(final NiFiTestUser user) throws Exception {
|
||||
String url = helper.getBaseUrl() + "/process-groups/root/processors";
|
||||
|
||||
// create the processor
|
||||
ProcessorDTO processor = new ProcessorDTO();
|
||||
processor.setName("execute code restricted");
|
||||
processor.setType(ExecuteCodeRestrictedProcessor.class.getName());
|
||||
|
||||
// create the revision
|
||||
final RevisionDTO revision = new RevisionDTO();
|
||||
revision.setClientId(READ_WRITE_CLIENT_ID);
|
||||
revision.setVersion(0L);
|
||||
|
||||
// create the entity body
|
||||
ProcessorEntity entity = new ProcessorEntity();
|
||||
entity.setRevision(revision);
|
||||
entity.setComponent(processor);
|
||||
|
||||
// perform the request as a user with read/write but no restricted access
|
||||
Response response = helper.getReadWriteUser().testPost(url, entity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// perform the request as a user with read/write and restricted access
|
||||
response = user.testPost(url, entity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final ProcessorEntity responseEntity = response.readEntity(ProcessorEntity.class);
|
||||
|
||||
// remove the restricted component
|
||||
deleteRestrictedComponent(responseEntity, user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -459,7 +513,7 @@ public class ITProcessorAccessControl {
|
||||
@Test
|
||||
public void testCopyPasteRestrictedProcessor() throws Exception {
|
||||
final String copyUrl = helper.getBaseUrl() + "/process-groups/root/snippet-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent();
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent(RestrictedProcessor.class.getName(), helper.getPrivilegedUser());
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// build the copy/paste request
|
||||
@ -474,6 +528,12 @@ public class ITProcessorAccessControl {
|
||||
// ensure the request failed... need privileged users since snippet comprised of the restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// perform the request as a user with read/write and only execute code restricted access
|
||||
response = helper.getExecuteCodeUser().testPost(copyUrl, copyRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getPrivilegedUser().testPost(copyUrl, copyRequest);
|
||||
|
||||
@ -483,8 +543,49 @@ public class ITProcessorAccessControl {
|
||||
final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
|
||||
|
||||
// remove the restricted processors
|
||||
deleteRestrictedComponent(tuple.getKey());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
|
||||
deleteRestrictedComponent(tuple.getKey(), helper.getPrivilegedUser());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null), helper.getPrivilegedUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests attempting to copy/paste a restricted processor requiring execute code permissions.
|
||||
*
|
||||
* @throws Exception ex
|
||||
*/
|
||||
@Test
|
||||
public void testCopyPasteExecuteCodeRestrictedProcessor() throws Exception {
|
||||
copyPasteExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
|
||||
copyPasteExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
|
||||
}
|
||||
|
||||
private void copyPasteExecuteCodeRestrictedProcessor(final NiFiTestUser user) throws Exception {
|
||||
final String copyUrl = helper.getBaseUrl() + "/process-groups/root/snippet-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent(ExecuteCodeRestrictedProcessor.class.getName(), user);
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// build the copy/paste request
|
||||
final CopySnippetRequestEntity copyRequest = new CopySnippetRequestEntity();
|
||||
copyRequest.setSnippetId(snippetEntity.getSnippet().getId());
|
||||
copyRequest.setOriginX(0.0);
|
||||
copyRequest.setOriginY(0.0);
|
||||
|
||||
// create the snippet
|
||||
Response response = helper.getReadWriteUser().testPost(copyUrl, copyRequest);
|
||||
|
||||
// ensure the request failed... need privileged users since snippet comprised of the restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// perform the request as a user with read/write and only execute code restricted access
|
||||
response = user.testPost(copyUrl, copyRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
|
||||
|
||||
// remove the restricted processors
|
||||
deleteRestrictedComponent(tuple.getKey(), user);
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null), user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -496,7 +597,7 @@ public class ITProcessorAccessControl {
|
||||
public void testTemplateWithRestrictedProcessor() throws Exception {
|
||||
final String createTemplateUrl = helper.getBaseUrl() + "/process-groups/root/templates";
|
||||
final String instantiateTemplateUrl = helper.getBaseUrl() + "/process-groups/root/template-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent();
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent(RestrictedProcessor.class.getName(), helper.getPrivilegedUser());
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// create the template
|
||||
@ -512,7 +613,7 @@ public class ITProcessorAccessControl {
|
||||
|
||||
response = helper.getReadWriteUser().testPost(createTemplateUrl, createTemplateRequest);
|
||||
|
||||
// ensure the request is successfull
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final TemplateEntity templateEntity = response.readEntity(TemplateEntity.class);
|
||||
@ -529,6 +630,12 @@ public class ITProcessorAccessControl {
|
||||
// ensure the request failed... need privileged user since the template is comprised of restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getExecuteCodeUser().testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
// ensure the request failed... need privileged user since the template is comprised of restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = helper.getPrivilegedUser().testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
@ -539,18 +646,79 @@ public class ITProcessorAccessControl {
|
||||
|
||||
// clean up the resources created during this test
|
||||
deleteTemplate(templateEntity);
|
||||
deleteRestrictedComponent(tuple.getKey());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null));
|
||||
deleteRestrictedComponent(tuple.getKey(), helper.getPrivilegedUser());
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null), helper.getPrivilegedUser());
|
||||
}
|
||||
|
||||
private Tuple<ProcessorEntity, SnippetEntity> createSnippetWithRestrictedComponent() throws Exception {
|
||||
/**
|
||||
* Tests attempting to use a template with a restricted processor requiring execute code permissions.
|
||||
*
|
||||
* @throws Exception ex
|
||||
*/
|
||||
@Test
|
||||
public void testTemplateWithExecuteCodeRestrictedProcessor() throws Exception {
|
||||
templateWithExecuteCodeRestrictedProcessor(helper.getPrivilegedUser());
|
||||
templateWithExecuteCodeRestrictedProcessor(helper.getExecuteCodeUser());
|
||||
}
|
||||
|
||||
private void templateWithExecuteCodeRestrictedProcessor(final NiFiTestUser user) throws Exception {
|
||||
final String createTemplateUrl = helper.getBaseUrl() + "/process-groups/root/templates";
|
||||
final String instantiateTemplateUrl = helper.getBaseUrl() + "/process-groups/root/template-instance";
|
||||
final Tuple<ProcessorEntity, SnippetEntity> tuple = createSnippetWithRestrictedComponent(ExecuteCodeRestrictedProcessor.class.getName(), helper.getPrivilegedUser());
|
||||
final SnippetEntity snippetEntity = tuple.getValue();
|
||||
|
||||
// create the template
|
||||
final CreateTemplateRequestEntity createTemplateRequest = new CreateTemplateRequestEntity();
|
||||
createTemplateRequest.setSnippetId(snippetEntity.getSnippet().getId());
|
||||
createTemplateRequest.setName("test");
|
||||
|
||||
// create the snippet
|
||||
Response response = helper.getWriteUser().testPost(createTemplateUrl, createTemplateRequest);
|
||||
|
||||
// ensure the request failed... need read perms to the components in the snippet
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
response = helper.getReadWriteUser().testPost(createTemplateUrl, createTemplateRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final TemplateEntity templateEntity = response.readEntity(TemplateEntity.class);
|
||||
|
||||
// build the template request
|
||||
final InstantiateTemplateRequestEntity instantiateTemplateRequest = new InstantiateTemplateRequestEntity();
|
||||
instantiateTemplateRequest.setTemplateId(templateEntity.getTemplate().getId());
|
||||
instantiateTemplateRequest.setOriginX(0.0);
|
||||
instantiateTemplateRequest.setOriginY(0.0);
|
||||
|
||||
// create the snippet
|
||||
response = helper.getReadWriteUser().testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
// ensure the request failed... need privileged user since the template is comprised of restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
// create the snippet
|
||||
response = user.testPost(instantiateTemplateUrl, instantiateTemplateRequest);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
|
||||
final FlowEntity flowEntity = response.readEntity(FlowEntity.class);
|
||||
|
||||
// clean up the resources created during this test
|
||||
deleteTemplate(templateEntity);
|
||||
deleteRestrictedComponent(tuple.getKey(), user);
|
||||
deleteRestrictedComponent(flowEntity.getFlow().getProcessors().stream().findFirst().orElse(null), user);
|
||||
}
|
||||
|
||||
private Tuple<ProcessorEntity, SnippetEntity> createSnippetWithRestrictedComponent(final String restrictedClassName, final NiFiTestUser user) throws Exception {
|
||||
final String processorUrl = helper.getBaseUrl() + "/process-groups/root/processors";
|
||||
final String snippetUrl = helper.getBaseUrl() + "/snippets";
|
||||
|
||||
// create the processor
|
||||
ProcessorDTO processor = new ProcessorDTO();
|
||||
processor.setName("restricted");
|
||||
processor.setType(RestrictedProcessor.class.getName());
|
||||
processor.setType(restrictedClassName);
|
||||
|
||||
// create the revision
|
||||
final RevisionDTO revision = new RevisionDTO();
|
||||
@ -563,7 +731,7 @@ public class ITProcessorAccessControl {
|
||||
entity.setComponent(processor);
|
||||
|
||||
// perform the request as a user with read/write and restricted access
|
||||
Response response = helper.getPrivilegedUser().testPost(processorUrl, entity);
|
||||
Response response = user.testPost(processorUrl, entity);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(201, response.getStatus());
|
||||
@ -604,7 +772,7 @@ public class ITProcessorAccessControl {
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
private void deleteRestrictedComponent(final ProcessorEntity entity) throws Exception {
|
||||
private void deleteRestrictedComponent(final ProcessorEntity entity, final NiFiTestUser user) throws Exception {
|
||||
if (entity == null) {
|
||||
Assert.fail("Failed to get Processor from template or snippet request.");
|
||||
return;
|
||||
@ -621,7 +789,7 @@ public class ITProcessorAccessControl {
|
||||
// ensure the request fails... needs access to restricted components
|
||||
assertEquals(403, response.getStatus());
|
||||
|
||||
response = helper.getPrivilegedUser().testDelete(entity.getUri(), queryParams);
|
||||
response = user.testDelete(entity.getUri(), queryParams);
|
||||
|
||||
// ensure the request is successful
|
||||
assertEquals(200, response.getStatus());
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.integration.util;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.processor.AbstractSessionFactoryProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSessionFactory;
|
||||
import org.apache.nifi.processor.ProcessorInitializationContext;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "specifically executes code")
|
||||
}
|
||||
)
|
||||
public class ExecuteCodeRestrictedProcessor extends AbstractSessionFactoryProcessor {
|
||||
|
||||
public ExecuteCodeRestrictedProcessor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Relationship> getRelationships() {
|
||||
final Set<Relationship> rels = new HashSet<>();
|
||||
rels.add(new Relationship.Builder().name("success").build());
|
||||
return rels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(final ProcessContext context, final ProcessSessionFactory sessionFactory) throws ProcessException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(final ProcessorInitializationContext context) {
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
|
||||
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
|
||||
/**
|
||||
* Contains extra rules to convenience when in component based access control tests.
|
||||
@ -40,6 +41,7 @@ public class NiFiTestAuthorizer implements Authorizer {
|
||||
public static final String WRITE_USER_DN = "write@nifi";
|
||||
public static final String READ_WRITE_USER_DN = "readwrite@nifi";
|
||||
public static final String PRIVILEGED_USER_DN = "privileged@nifi";
|
||||
public static final String EXECUTED_CODE_USER_DN = "executecode@nifi";
|
||||
|
||||
public static final String TOKEN_USER = "user@nifi";
|
||||
|
||||
@ -88,15 +90,28 @@ public class NiFiTestAuthorizer implements Authorizer {
|
||||
}
|
||||
}
|
||||
|
||||
// execute code access
|
||||
if (ResourceFactory.getRestrictedComponentsResource(RequiredPermission.EXECUTE_CODE).getIdentifier().equals(request.getResource().getIdentifier())) {
|
||||
if (EXECUTED_CODE_USER_DN.equals(request.getIdentity())) {
|
||||
return AuthorizationResult.approved();
|
||||
} else {
|
||||
return AuthorizationResult.denied();
|
||||
}
|
||||
}
|
||||
|
||||
// read access
|
||||
if (READ_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) || PRIVILEGED_USER_DN.equals(request.getIdentity())) {
|
||||
if (READ_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) ||
|
||||
PRIVILEGED_USER_DN.equals(request.getIdentity()) || EXECUTED_CODE_USER_DN.equals(request.getIdentity())) {
|
||||
|
||||
if (RequestAction.READ.equals(request.getAction())) {
|
||||
return AuthorizationResult.approved();
|
||||
}
|
||||
}
|
||||
|
||||
// write access
|
||||
if (WRITE_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) || PRIVILEGED_USER_DN.equals(request.getIdentity())) {
|
||||
if (WRITE_USER_DN.equals(request.getIdentity()) || READ_WRITE_USER_DN.equals(request.getIdentity()) ||
|
||||
PRIVILEGED_USER_DN.equals(request.getIdentity()) || EXECUTED_CODE_USER_DN.equals(request.getIdentity())) {
|
||||
|
||||
if (RequestAction.WRITE.equals(request.getAction())) {
|
||||
return AuthorizationResult.approved();
|
||||
}
|
||||
|
@ -27,7 +27,9 @@ import org.apache.nifi.processor.exception.ProcessException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Restricted("")
|
||||
@Restricted(
|
||||
value = "generally restricted"
|
||||
)
|
||||
public class RestrictedProcessor extends AbstractSessionFactoryProcessor {
|
||||
|
||||
public RestrictedProcessor() {
|
||||
|
@ -14,4 +14,5 @@
|
||||
# limitations under the License.
|
||||
org.apache.nifi.integration.util.SourceTestProcessor
|
||||
org.apache.nifi.integration.util.TerminationTestProcessor
|
||||
org.apache.nifi.integration.util.RestrictedProcessor
|
||||
org.apache.nifi.integration.util.RestrictedProcessor
|
||||
org.apache.nifi.integration.util.ExecuteCodeRestrictedProcessor
|
@ -30,6 +30,7 @@
|
||||
<div id="global-policy-controls" class="hidden policy-controls">
|
||||
<div id="policy-type-list"></div>
|
||||
<div id="controller-policy-target" class="hidden"></div>
|
||||
<div id="restricted-component-required-permissions" class="hidden"></div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<div id="component-policy-controls" class="hidden policy-controls">
|
||||
@ -90,6 +91,7 @@
|
||||
</div>
|
||||
<div id="policy-loading-container" class="loading-container"></div>
|
||||
<div id="admin-policy-message" class="hidden">Only listing component specific administrators. Inherited administrators not shown.</div>
|
||||
<div id="restriction-message" class="hidden">Only listing restriction specific users. Users with permission "regardless of restrictions" not shown but are also allowed.</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
@ -89,7 +89,7 @@ div.policy-controls {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#policy-type-list {
|
||||
#policy-type-list, #restricted-component-required-permissions {
|
||||
float: left;
|
||||
width: 225px;
|
||||
margin-right: 3px;
|
||||
@ -275,7 +275,7 @@ div.remove-allowed-entity {
|
||||
admin policy message
|
||||
*/
|
||||
|
||||
#admin-policy-message {
|
||||
#admin-policy-message, #restriction-message {
|
||||
float: right;
|
||||
margin-top: 8px;
|
||||
color: #775351;
|
||||
|
@ -288,7 +288,7 @@
|
||||
* @param item process type
|
||||
*/
|
||||
var isSelectable = function (item) {
|
||||
return nfCommon.isBlank(item.usageRestriction) || nfCommon.canAccessRestrictedComponents();
|
||||
return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
|
||||
};
|
||||
|
||||
function ProcessorComponent() {
|
||||
@ -436,9 +436,28 @@
|
||||
var item = processorTypesData.getItemById(rowId);
|
||||
|
||||
// show the tooltip
|
||||
if (nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
|
||||
if (item.restricted === true) {
|
||||
var restrictionTip = $('<div></div>');
|
||||
|
||||
if (nfCommon.isBlank(item.usageRestriction)) {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
|
||||
} else {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
|
||||
}
|
||||
|
||||
var restrictions = [];
|
||||
if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
|
||||
$.each(item.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
|
||||
});
|
||||
} else {
|
||||
restrictions.push('Access to restricted components regardless of restrictions.');
|
||||
}
|
||||
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
|
||||
|
||||
usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
|
||||
content: item.usageRestriction,
|
||||
content: restrictionTip,
|
||||
position: {
|
||||
container: $('#summary'),
|
||||
at: 'bottom right',
|
||||
@ -453,6 +472,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
|
||||
|
||||
// load the available processor types, this select is shown in the
|
||||
// new processor dialog when a processor is dragged onto the screen
|
||||
$.ajax({
|
||||
@ -462,6 +483,8 @@
|
||||
}).done(function (response) {
|
||||
var tags = [];
|
||||
var groups = d3.set();
|
||||
var restrictedUsage = d3.map();
|
||||
var requiredPermissions = d3.map();
|
||||
|
||||
// begin the update
|
||||
processorTypesData.beginUpdate();
|
||||
@ -470,6 +493,46 @@
|
||||
$.each(response.processorTypes, function (i, documentedType) {
|
||||
var type = documentedType.type;
|
||||
|
||||
if (documentedType.restricted === true) {
|
||||
if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
|
||||
$.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(requiredPermission.id)) {
|
||||
requiredPermissions.set(requiredPermission.id, requiredPermission.label);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(requiredPermission.id)) {
|
||||
restrictedUsage.set(requiredPermission.id, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(requiredPermission.id).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(generalRestriction.value)) {
|
||||
requiredPermissions.set(generalRestriction.value, generalRestriction.text);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(generalRestriction.value)) {
|
||||
restrictedUsage.set(generalRestriction.value, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(generalRestriction.value).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// record the group
|
||||
groups.add(documentedType.bundle.group);
|
||||
|
||||
@ -480,7 +543,9 @@
|
||||
type: type,
|
||||
bundle: documentedType.bundle,
|
||||
description: nfCommon.escapeHtml(documentedType.description),
|
||||
restricted: documentedType.restricted,
|
||||
usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
|
||||
explicitRestrictions: documentedType.explicitRestrictions,
|
||||
tags: documentedType.tags.join(', ')
|
||||
});
|
||||
|
||||
@ -497,6 +562,9 @@
|
||||
processorTypesData.reSort();
|
||||
processorTypesGrid.invalidate();
|
||||
|
||||
// set the component restrictions and the corresponding required permissions
|
||||
nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
|
||||
|
||||
// set the total number of processors
|
||||
$('#total-processor-types, #displayed-processor-types').text(response.processorTypes.length);
|
||||
|
||||
|
@ -56,6 +56,9 @@
|
||||
var nfBirdseye;
|
||||
var nfGraph;
|
||||
|
||||
var restrictedUsage = d3.map();
|
||||
var requiredPermissions = d3.map();
|
||||
|
||||
var config = {
|
||||
storage: {
|
||||
namePrefix: 'nifi-view-'
|
||||
@ -1842,6 +1845,41 @@
|
||||
return nfCanvas.isConfigurableUsersAndGroups();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the restricted usage and the required permissions.
|
||||
*
|
||||
* @param additionalRestrictedUsages
|
||||
* @param additionalRequiredPermissions
|
||||
*/
|
||||
addComponentRestrictions: function (additionalRestrictedUsages, additionalRequiredPermissions) {
|
||||
additionalRestrictedUsages.each(function (componentRestrictions, requiredPermissionId) {
|
||||
if (!restrictedUsage.has(requiredPermissionId)) {
|
||||
restrictedUsage.set(requiredPermissionId, []);
|
||||
}
|
||||
|
||||
componentRestrictions.forEach(function (componentRestriction) {
|
||||
restrictedUsage.get(requiredPermissionId).push(componentRestriction);
|
||||
});
|
||||
});
|
||||
additionalRequiredPermissions.each(function (requiredPermissionLabel, requiredPermissionId) {
|
||||
if (!requiredPermissions.has(requiredPermissionId)) {
|
||||
requiredPermissions.set(requiredPermissionId, requiredPermissionLabel);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the component restrictions and the require permissions.
|
||||
*
|
||||
* @returns {{restrictedUsage: map, requiredPermissions: map}} component restrictions
|
||||
*/
|
||||
getComponentRestrictions: function () {
|
||||
return {
|
||||
restrictedUsage: restrictedUsage,
|
||||
requiredPermissions: requiredPermissions
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the group id.
|
||||
*
|
||||
|
@ -106,7 +106,7 @@
|
||||
* @param item controller service type
|
||||
*/
|
||||
var isSelectable = function (item) {
|
||||
return nfCommon.isBlank(item.usageRestriction) || nfCommon.canAccessRestrictedComponents();
|
||||
return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -462,9 +462,28 @@
|
||||
var item = controllerServiceTypesData.getItemById(rowId);
|
||||
|
||||
// show the tooltip
|
||||
if (nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
|
||||
if (item.restricted === true) {
|
||||
var restrictionTip = $('<div></div>');
|
||||
|
||||
if (nfCommon.isBlank(item.usageRestriction)) {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
|
||||
} else {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
|
||||
}
|
||||
|
||||
var restrictions = [];
|
||||
if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
|
||||
$.each(item.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
|
||||
});
|
||||
} else {
|
||||
restrictions.push('Access to restricted components regardless of restrictions.');
|
||||
}
|
||||
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
|
||||
|
||||
usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
|
||||
content: item.usageRestriction,
|
||||
content: restrictionTip,
|
||||
position: {
|
||||
container: $('#summary'),
|
||||
at: 'bottom right',
|
||||
@ -508,6 +527,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
|
||||
|
||||
// load the available controller services
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
@ -517,12 +538,54 @@
|
||||
var id = 0;
|
||||
var tags = [];
|
||||
var groups = d3.set();
|
||||
var restrictedUsage = d3.map();
|
||||
var requiredPermissions = d3.map();
|
||||
|
||||
// begin the update
|
||||
controllerServiceTypesData.beginUpdate();
|
||||
|
||||
// go through each controller service type
|
||||
$.each(response.controllerServiceTypes, function (i, documentedType) {
|
||||
if (documentedType.restricted === true) {
|
||||
if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
|
||||
$.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(requiredPermission.id)) {
|
||||
requiredPermissions.set(requiredPermission.id, requiredPermission.label);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(requiredPermission.id)) {
|
||||
restrictedUsage.set(requiredPermission.id, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(requiredPermission.id).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: explicitRestriction.explanation
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(generalRestriction.value)) {
|
||||
requiredPermissions.set(generalRestriction.value, generalRestriction.text);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(generalRestriction.value)) {
|
||||
restrictedUsage.set(generalRestriction.value, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(generalRestriction.value).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: documentedType.usageRestriction
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// record the group
|
||||
groups.add(documentedType.bundle.group);
|
||||
|
||||
@ -534,7 +597,9 @@
|
||||
bundle: documentedType.bundle,
|
||||
controllerServiceApis: documentedType.controllerServiceApis,
|
||||
description: nfCommon.escapeHtml(documentedType.description),
|
||||
restricted: documentedType.restricted,
|
||||
usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
|
||||
explicitRestrictions: documentedType.explicitRestrictions,
|
||||
tags: documentedType.tags.join(', ')
|
||||
});
|
||||
|
||||
@ -551,6 +616,9 @@
|
||||
controllerServiceTypesData.reSort();
|
||||
controllerServiceTypesGrid.invalidate();
|
||||
|
||||
// set the component restrictions and the corresponding required permissions
|
||||
nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
|
||||
|
||||
// set the total number of processors
|
||||
$('#total-controller-service-types, #displayed-controller-service-types').text(response.controllerServiceTypes.length);
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
};
|
||||
|
||||
var initialized = false;
|
||||
var initializedComponentRestrictions = false;
|
||||
|
||||
var initAddTenantToPolicyDialog = function () {
|
||||
$('#new-policy-user-button').on('click', function () {
|
||||
@ -418,7 +419,10 @@
|
||||
|
||||
// if the option is for a specific component
|
||||
if (globalPolicySupportsReadWrite(option.value)) {
|
||||
// update the policy target and let it relaod the policy
|
||||
$('#restricted-component-required-permissions').hide();
|
||||
$('#restriction-message').hide();
|
||||
|
||||
// update the policy target and let it reload the policy
|
||||
$('#controller-policy-target').combo('setSelectedOption', {
|
||||
'value': 'read'
|
||||
}).show();
|
||||
@ -432,6 +436,59 @@
|
||||
$('#selected-policy-action').text('read');
|
||||
}
|
||||
|
||||
// handle any granular restrictions
|
||||
if (option.value === 'restricted-components') {
|
||||
if (!initializedComponentRestrictions) {
|
||||
var regardlessOfRestrictions = 'regardless of restrictions';
|
||||
var componentRestrictions = nfCanvasUtils.getComponentRestrictions();
|
||||
var requiredPermissions = componentRestrictions.requiredPermissions;
|
||||
|
||||
var options = [{
|
||||
text: regardlessOfRestrictions,
|
||||
value: '',
|
||||
description: 'Allows users to create/modify all restricted components regardless of restrictions.'
|
||||
}];
|
||||
|
||||
requiredPermissions.each(function (label, id) {
|
||||
if (id !== option.value) {
|
||||
options.push({
|
||||
text: "requiring '" + label + "'",
|
||||
value: id,
|
||||
description: "Allows users to create/modify restricted components requiring '" + nfCommon.escapeHtml(label) + "'"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
options.sort(function (a, b) {
|
||||
if (a.text === regardlessOfRestrictions) {
|
||||
return -1;
|
||||
} else if (b.text === regardlessOfRestrictions) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a.text < b.text ? -1 : a.text > b.text ? 1 : 0;
|
||||
});
|
||||
|
||||
$('#restricted-component-required-permissions').combo({
|
||||
options: options,
|
||||
select: function (restrictionOption) {
|
||||
if (restrictionOption.text === regardlessOfRestrictions) {
|
||||
$('#restriction-message').hide();
|
||||
} else {
|
||||
$('#restriction-message').show();
|
||||
}
|
||||
|
||||
loadPolicy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#restricted-component-required-permissions').show();
|
||||
} else {
|
||||
$('#restriction-message').hide();
|
||||
$('#restricted-component-required-permissions').hide();
|
||||
}
|
||||
|
||||
// reload the policy
|
||||
loadPolicy();
|
||||
}
|
||||
@ -766,6 +823,14 @@
|
||||
resource += ('/' + componentId);
|
||||
}
|
||||
|
||||
// identify more granular restrict component access if applicable
|
||||
if (resource === 'restricted-components') {
|
||||
var requiredPermission = $('#restricted-component-required-permissions').combo('getSelectedOption').value;
|
||||
if (!nfCommon.isBlank(requiredPermission)) {
|
||||
resource += ('/' + requiredPermission);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
'action': $('#selected-policy-action').text(),
|
||||
'resource': '/' + resource
|
||||
@ -909,7 +974,10 @@
|
||||
|
||||
var policyDeferred;
|
||||
if (resourceAndAction.resource.startsWith('/policies')) {
|
||||
$('#admin-policy-message').show();
|
||||
// if this is a component specific policy permission, show the admin policy message
|
||||
if (resourceAndAction.resource.endsWith('/policies')) {
|
||||
$('#admin-policy-message').show();
|
||||
}
|
||||
|
||||
policyDeferred = $.Deferred(function (deferred) {
|
||||
$.ajax({
|
||||
@ -980,6 +1048,87 @@
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
deferred.reject();
|
||||
nfErrorHandler.handleAjaxError(xhr, status, error);
|
||||
}
|
||||
});
|
||||
}).promise();
|
||||
} else if (resourceAndAction.resource.startsWith('/restricted-components')) {
|
||||
$('#admin-policy-message').hide();
|
||||
|
||||
policyDeferred = $.Deferred(function (deferred) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '../nifi-api/policies/' + resourceAndAction.action + resourceAndAction.resource,
|
||||
dataType: 'json'
|
||||
}).done(function (policyEntity) {
|
||||
// update the refresh timestamp
|
||||
$('#policy-last-refreshed').text(policyEntity.generated);
|
||||
|
||||
// ensure appropriate actions for the loaded policy
|
||||
if (policyEntity.permissions.canRead === true) {
|
||||
var policy = policyEntity.component;
|
||||
|
||||
// if the return policy is for the desired policy (not inherited, show it)
|
||||
if (resourceAndAction.resource === policy.resource) {
|
||||
// populate the policy details
|
||||
populatePolicy(policyEntity);
|
||||
} else {
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
// show an appropriate message
|
||||
$('#policy-message').text('No restriction specific users.');
|
||||
|
||||
if (nfCanvasUtils.isConfigurableAuthorizer()) {
|
||||
// we don't know if the user has permissions to the desired policy... show create button and allow the server to decide
|
||||
$('#new-policy-message').show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
// show an appropriate message
|
||||
$('#policy-message').text('Not authorized to view the policy.');
|
||||
|
||||
if (nfCanvasUtils.isConfigurableAuthorizer()) {
|
||||
// we don't know if the user has permissions to the desired policy... show create button and allow the server to decide
|
||||
$('#new-policy-message').show();
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}).fail(function (xhr, status, error) {
|
||||
if (xhr.status === 404) {
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
// show an appropriate message
|
||||
if (resourceAndAction.resource === '/restricted-components') {
|
||||
$('#policy-message').text('No users with permission "regardless of restrictions."');
|
||||
} else {
|
||||
$('#policy-message').text('No users with permission to specific restriction.');
|
||||
}
|
||||
|
||||
if (nfCanvasUtils.isConfigurableAuthorizer()) {
|
||||
// we don't know if the user has permissions to the desired policy... show create button and allow the server to decide
|
||||
$('#new-policy-message').show();
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
} else if (xhr.status === 403) {
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
// show an appropriate message
|
||||
$('#policy-message').text('Not authorized to access the policy for the specified resource.');
|
||||
|
||||
deferred.resolve();
|
||||
} else {
|
||||
// reset the policy
|
||||
resetPolicy();
|
||||
|
||||
deferred.reject();
|
||||
nfErrorHandler.handleAjaxError(xhr, status, error);
|
||||
}
|
||||
|
@ -218,7 +218,7 @@
|
||||
* @param item reporting task type
|
||||
*/
|
||||
var isSelectable = function (item) {
|
||||
return nfCommon.isBlank(item.usageRestriction) || nfCommon.canAccessRestrictedComponents();
|
||||
return item.restricted === false || nfCommon.canAccessComponentRestrictions(item.explicitRestrictions);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -682,9 +682,28 @@
|
||||
var item = reportingTaskTypesData.getItemById(rowId);
|
||||
|
||||
// show the tooltip
|
||||
if (nfCommon.isDefinedAndNotNull(item.usageRestriction)) {
|
||||
if (item.restricted === true) {
|
||||
var restrictionTip = $('<div></div>');
|
||||
|
||||
if (nfCommon.isBlank(item.usageRestriction)) {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text('Requires the following permissions:'));
|
||||
} else {
|
||||
restrictionTip.append($('<p style="margin-bottom: 3px;"></p>').text(item.usageRestriction + ' Requires the following permissions:'));
|
||||
}
|
||||
|
||||
var restrictions = [];
|
||||
if (nfCommon.isDefinedAndNotNull(item.explicitRestrictions)) {
|
||||
$.each(item.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
restrictions.push("'" + requiredPermission.label + "' - " + nfCommon.escapeHtml(explicitRestriction.explanation));
|
||||
});
|
||||
} else {
|
||||
restrictions.push('Access to restricted components regardless of restrictions.');
|
||||
}
|
||||
restrictionTip.append(nfCommon.formatUnorderedList(restrictions));
|
||||
|
||||
usageRestriction.qtip($.extend({}, nfCommon.config.tooltipConfig, {
|
||||
content: item.usageRestriction,
|
||||
content: restrictionTip,
|
||||
position: {
|
||||
container: $('#summary'),
|
||||
at: 'bottom right',
|
||||
@ -699,6 +718,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
var generalRestriction = nfCommon.getPolicyTypeListing('restricted-components');
|
||||
|
||||
// load the available reporting tasks
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
@ -708,12 +729,54 @@
|
||||
var id = 0;
|
||||
var tags = [];
|
||||
var groups = d3.set();
|
||||
var restrictedUsage = d3.map();
|
||||
var requiredPermissions = d3.map();
|
||||
|
||||
// begin the update
|
||||
reportingTaskTypesData.beginUpdate();
|
||||
|
||||
// go through each reporting task type
|
||||
$.each(response.reportingTaskTypes, function (i, documentedType) {
|
||||
if (documentedType.restricted === true) {
|
||||
if (nfCommon.isDefinedAndNotNull(documentedType.explicitRestrictions)) {
|
||||
$.each(documentedType.explicitRestrictions, function (_, explicitRestriction) {
|
||||
var requiredPermission = explicitRestriction.requiredPermission;
|
||||
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(requiredPermission.id)) {
|
||||
requiredPermissions.set(requiredPermission.id, requiredPermission.label);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(requiredPermission.id)) {
|
||||
restrictedUsage.set(requiredPermission.id, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(requiredPermission.id).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: nfCommon.escapeHtml(explicitRestriction.explanation)
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// update required permissions
|
||||
if (!requiredPermissions.has(generalRestriction.value)) {
|
||||
requiredPermissions.set(generalRestriction.value, generalRestriction.text);
|
||||
}
|
||||
|
||||
// update component restrictions
|
||||
if (!restrictedUsage.has(generalRestriction.value)) {
|
||||
restrictedUsage.set(generalRestriction.value, []);
|
||||
}
|
||||
|
||||
restrictedUsage.get(generalRestriction.value).push({
|
||||
type: nfCommon.formatType(documentedType),
|
||||
bundle: nfCommon.formatBundle(documentedType.bundle),
|
||||
explanation: nfCommon.escapeHtml(documentedType.usageRestriction)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// record the group
|
||||
groups.add(documentedType.bundle.group);
|
||||
|
||||
@ -724,7 +787,9 @@
|
||||
type: documentedType.type,
|
||||
bundle: documentedType.bundle,
|
||||
description: nfCommon.escapeHtml(documentedType.description),
|
||||
restricted: documentedType.restricted,
|
||||
usageRestriction: nfCommon.escapeHtml(documentedType.usageRestriction),
|
||||
explicitRestrictions: documentedType.explicitRestrictions,
|
||||
tags: documentedType.tags.join(', ')
|
||||
});
|
||||
|
||||
@ -741,6 +806,9 @@
|
||||
reportingTaskTypesData.reSort();
|
||||
reportingTaskTypesGrid.invalidate();
|
||||
|
||||
// set the component restrictions and the corresponding required permissions
|
||||
nfCanvasUtils.addComponentRestrictions(restrictedUsage, requiredPermissions);
|
||||
|
||||
// set the total number of processors
|
||||
$('#total-reporting-task-types, #displayed-reporting-task-types').text(response.reportingTaskTypes.length);
|
||||
|
||||
|
@ -119,7 +119,7 @@
|
||||
}, {
|
||||
text: 'access restricted components',
|
||||
value: 'restricted-components',
|
||||
description: 'Allows users to create/modify restricted components assuming otherwise sufficient permissions'
|
||||
description: 'Allows users to create/modify restricted components assuming other permissions are sufficient'
|
||||
}, {
|
||||
text: 'access all policies',
|
||||
value: 'policies',
|
||||
@ -315,7 +315,7 @@
|
||||
var markup = '';
|
||||
|
||||
// restriction
|
||||
if (nfCommon.isBlank(dataContext.usageRestriction) === false) {
|
||||
if (dataContext.restricted === true) {
|
||||
markup += '<div class="view-usage-restriction fa fa-shield"></div><span class="hidden row-id">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
|
||||
} else {
|
||||
markup += '<div class="fa"></div>';
|
||||
@ -590,7 +590,7 @@
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the current user can access restricted comopnents.
|
||||
* Determines whether the current user can access restricted components.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
@ -602,6 +602,56 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the current user can access the specific explicit component restrictions.
|
||||
*
|
||||
* @param {object} explicitRestrictions
|
||||
* @returns {boolean}
|
||||
*/
|
||||
canAccessComponentRestrictions: function (explicitRestrictions) {
|
||||
if (nfCommon.isDefinedAndNotNull(nfCommon.currentUser)) {
|
||||
if (nfCommon.currentUser.restrictedComponentsPermissions.canWrite === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var satisfiesRequiredPermission = function (requiredPermission) {
|
||||
if (nfCommon.isEmpty(nfCommon.currentUser.componentRestrictionPermissions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var hasPermission = false;
|
||||
|
||||
$.each(nfCommon.currentUser.componentRestrictionPermissions, function (_, componentRestrictionPermission) {
|
||||
if (componentRestrictionPermission.requiredPermission.id === requiredPermission.id) {
|
||||
if (componentRestrictionPermission.permissions.canWrite === true) {
|
||||
hasPermission = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return hasPermission;
|
||||
};
|
||||
|
||||
var satisfiesRequiredPermissions = true;
|
||||
|
||||
if (nfCommon.isEmpty(explicitRestrictions)) {
|
||||
satisfiesRequiredPermissions = false;
|
||||
} else {
|
||||
$.each(explicitRestrictions, function (_, explicitRestriction) {
|
||||
if (!satisfiesRequiredPermission(explicitRestriction.requiredPermission)) {
|
||||
satisfiesRequiredPermissions = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return satisfiesRequiredPermissions;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the current user can access counters.
|
||||
*
|
||||
|
@ -517,7 +517,7 @@
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a human readable global policy strung.
|
||||
* Generates a human readable global policy string.
|
||||
*
|
||||
* @param dataContext
|
||||
* @returns {string}
|
||||
@ -527,6 +527,23 @@
|
||||
nfCommon.getPolicyTypeListing(nfCommon.substringAfterFirst(dataContext.component.resource, '/')).text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a human readable restricted component policy string.
|
||||
*
|
||||
* @param dataContext
|
||||
* @returns {string}
|
||||
*/
|
||||
var restrictedComponentResourceParser = function (dataContext) {
|
||||
var resource = dataContext.component.resource;
|
||||
|
||||
if (resource === '/restricted-components') {
|
||||
return 'Restricted components regardless of restrictions';
|
||||
}
|
||||
|
||||
var subResource = nfCommon.substringAfterFirst(resource, '/restricted-components/');
|
||||
return "Restricted components requiring '" + subResource + "'";
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a human readable component policy string.
|
||||
*
|
||||
@ -591,12 +608,7 @@
|
||||
var policyDisplayNameFormatter = function (row, cell, value, columnDef, dataContext) {
|
||||
// if the user has permission to the policy
|
||||
if (dataContext.permissions.canRead === true) {
|
||||
// check if Global policy
|
||||
if (nfCommon.isUndefinedOrNull(dataContext.component.componentReference)) {
|
||||
return globalResourceParser(dataContext);
|
||||
}
|
||||
// not a global policy... check if user has access to the component reference
|
||||
return componentResourceParser(dataContext);
|
||||
return formatPolicy(dataContext);
|
||||
} else {
|
||||
return '<span class="unset">' + nfCommon.escapeHtml(dataContext.id) + '</span>';
|
||||
}
|
||||
@ -942,6 +954,25 @@
|
||||
data.sort(comparer, sortDetails.sortAsc);
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the specified policy.
|
||||
*
|
||||
* @param dataContext
|
||||
* @returns {string}
|
||||
*/
|
||||
var formatPolicy = function (dataContext) {
|
||||
if (dataContext.component.resource.startsWith('/restricted-components')) {
|
||||
// restricted components policy
|
||||
return restrictedComponentResourceParser(dataContext);
|
||||
} else if (nfCommon.isUndefinedOrNull(dataContext.component.componentReference)) {
|
||||
// global policy
|
||||
return globalResourceParser(dataContext);
|
||||
} else {
|
||||
// not restricted/global policy... check if user has access to the component reference
|
||||
return componentResourceParser(dataContext);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts the specified data using the specified sort details.
|
||||
*
|
||||
@ -962,26 +993,14 @@
|
||||
|
||||
// if the user has permission to the policy
|
||||
if (a.permissions.canRead === true) {
|
||||
// check if Global policy
|
||||
if (nfCommon.isUndefinedOrNull(a.component.componentReference)) {
|
||||
aString = globalResourceParser(a);
|
||||
} else {
|
||||
// not a global policy... check if user has access to the component reference
|
||||
aString = componentResourceParser(a);
|
||||
}
|
||||
aString = formatPolicy(a);
|
||||
} else {
|
||||
aString = a.id;
|
||||
}
|
||||
|
||||
// if the user has permission to the policy
|
||||
if (b.permissions.canRead === true) {
|
||||
// check if Global policy
|
||||
if (nfCommon.isUndefinedOrNull(b.component.componentReference)) {
|
||||
bString = globalResourceParser(b);
|
||||
} else {
|
||||
// not a global policy... check if user has access to the component reference
|
||||
bString = componentResourceParser(b);
|
||||
}
|
||||
bString = formatPolicy(b);
|
||||
} else {
|
||||
bString = b.id;
|
||||
}
|
||||
|
@ -16,28 +16,22 @@
|
||||
*/
|
||||
package org.apache.nifi.processors.groovyx;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.Script;
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.EventDriven;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.ControllerService;
|
||||
import org.apache.nifi.dbcp.DBCPService;
|
||||
import org.apache.nifi.processor.AbstractProcessor;
|
||||
@ -47,20 +41,25 @@ import org.apache.nifi.processor.ProcessorInitializationContext;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.processors.groovyx.flow.GroovyProcessSessionWrap;
|
||||
import org.apache.nifi.processors.groovyx.sql.OSql;
|
||||
import org.apache.nifi.processors.groovyx.util.Files;
|
||||
import org.apache.nifi.processors.groovyx.util.Validators;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.runtime.ResourceGroovyMethods;
|
||||
import org.codehaus.groovy.runtime.StackTraceUtils;
|
||||
|
||||
import org.apache.nifi.processors.groovyx.sql.OSql;
|
||||
import org.apache.nifi.processors.groovyx.util.Files;
|
||||
import org.apache.nifi.processors.groovyx.util.Validators;
|
||||
import org.apache.nifi.processors.groovyx.flow.GroovyProcessSessionWrap;
|
||||
|
||||
import groovy.lang.GroovyShell;
|
||||
import groovy.lang.Script;
|
||||
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@EventDriven
|
||||
@InputRequirement(InputRequirement.Requirement.INPUT_ALLOWED)
|
||||
@ -69,7 +68,13 @@ import org.apache.nifi.components.ValidationContext;
|
||||
"Experimental Extended Groovy script processor. The script is responsible for "
|
||||
+ "handling the incoming flow file (transfer to SUCCESS or remove, e.g.) as well as any flow files created by "
|
||||
+ "the script. If the handling is incomplete or incorrect, the session will be rolled back.")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
@SeeAlso(classNames={"org.apache.nifi.processors.script.ExecuteScript"})
|
||||
@DynamicProperty(name = "A script engine property to update",
|
||||
value = "The value to set it to",
|
||||
|
@ -16,6 +16,29 @@
|
||||
*/
|
||||
package org.apache.nifi.processors.hadoop;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -26,28 +49,6 @@ import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@TriggerWhenEmpty
|
||||
@InputRequirement(InputRequirement.Requirement.INPUT_ALLOWED)
|
||||
@Tags({"hadoop", "HDFS", "delete", "remove", "filesystem", "restricted"})
|
||||
@ -58,7 +59,16 @@ import com.google.common.collect.Maps;
|
||||
+ " no incoming connections no flowfiles will be transfered to any output relationships. If there is an incoming"
|
||||
+ " flowfile then provided there are no detected failures it will be transferred to success otherwise it will be sent to false. If"
|
||||
+ " knowledge of globbed files deleted is necessary use ListHDFS first to produce a specific list of files to delete. ")
|
||||
@Restricted("Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
@WritesAttributes({
|
||||
@WritesAttribute(attribute="hdfs.filename", description="HDFS file to be deleted. "
|
||||
+ "If multiple files are deleted, then only the last filename is set."),
|
||||
|
@ -28,12 +28,14 @@ import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.SupportsBatching;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
@ -61,7 +63,16 @@ import java.util.concurrent.TimeUnit;
|
||||
@WritesAttribute(attribute="hdfs.failure.reason", description="When a FlowFile is routed to 'failure', this attribute is added indicating why the file could "
|
||||
+ "not be fetched from HDFS")
|
||||
@SeeAlso({ListHDFS.class, GetHDFS.class, PutHDFS.class})
|
||||
@Restricted("Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class FetchHDFS extends AbstractHadoopProcessor {
|
||||
|
||||
static final PropertyDescriptor FILENAME = new PropertyDescriptor.Builder()
|
||||
|
@ -29,6 +29,7 @@ import org.apache.hadoop.io.compress.CompressionCodecFactory;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
@ -37,6 +38,7 @@ import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
@ -76,7 +78,19 @@ import java.util.regex.Pattern;
|
||||
+ "is set to /tmp, then files picked up from /tmp will have the path attribute set to \"./\". If the Recurse Subdirectories property is set to true and "
|
||||
+ "a file is picked up from /tmp/abc/1/2/3, then the path attribute will be set to \"abc/1/2/3\".") })
|
||||
@SeeAlso({PutHDFS.class, ListHDFS.class})
|
||||
@Restricted("Provides operator the ability to retrieve and delete any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class GetHDFS extends AbstractHadoopProcessor {
|
||||
|
||||
public static final String BUFFER_SIZE_KEY = "io.file.buffer.size";
|
||||
|
@ -16,6 +16,35 @@
|
||||
*/
|
||||
package org.apache.nifi.processors.hadoop;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.FileUtil;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.fs.PathFilter;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.util.StopWatch;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.PrivilegedAction;
|
||||
@ -32,32 +61,6 @@ import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.FileUtil;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.fs.PathFilter;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.util.StopWatch;
|
||||
|
||||
/**
|
||||
* This processor renames files on HDFS.
|
||||
*/
|
||||
@ -68,6 +71,19 @@ import org.apache.nifi.util.StopWatch;
|
||||
@WritesAttribute(attribute = "filename", description = "The name of the file written to HDFS is stored in this attribute."),
|
||||
@WritesAttribute(attribute = "absolute.hdfs.path", description = "The absolute path to the file on HDFS is stored in this attribute.")})
|
||||
@SeeAlso({PutHDFS.class, GetHDFS.class})
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class MoveHDFS extends AbstractHadoopProcessor {
|
||||
|
||||
// static global
|
||||
|
@ -27,6 +27,7 @@ import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
@ -35,6 +36,7 @@ import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.PropertyValue;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.DataUnit;
|
||||
@ -72,7 +74,16 @@ import java.util.concurrent.TimeUnit;
|
||||
@WritesAttribute(attribute = "absolute.hdfs.path", description = "The absolute path to the file on HDFS is stored in this attribute.")
|
||||
})
|
||||
@SeeAlso(GetHDFS.class)
|
||||
@Restricted("Provides operator the ability to write to any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class PutHDFS extends AbstractHadoopProcessor {
|
||||
|
||||
public static final String REPLACE_RESOLUTION = "replace";
|
||||
|
@ -21,12 +21,14 @@ import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.SupportsBatching;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processors.hadoop.AbstractFetchHDFSRecord;
|
||||
@ -50,7 +52,16 @@ import java.io.IOException;
|
||||
@WritesAttribute(attribute = "record.count", description = "The number of records in the resulting flow file")
|
||||
})
|
||||
@SeeAlso({PutParquet.class})
|
||||
@Restricted("Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to retrieve any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class FetchParquet extends AbstractFetchHDFSRecord {
|
||||
|
||||
@Override
|
||||
|
@ -23,6 +23,7 @@ import org.apache.hadoop.fs.Path;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
@ -30,6 +31,7 @@ import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.avro.AvroTypeUtil;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.DataUnit;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
@ -67,7 +69,16 @@ import java.util.List;
|
||||
@WritesAttribute(attribute = "absolute.hdfs.path", description = "The absolute path to the file is stored in this attribute."),
|
||||
@WritesAttribute(attribute = "record.count", description = "The number of records written to the Parquet file")
|
||||
})
|
||||
@Restricted("Provides operator the ability to write to any file that NiFi has access to in HDFS or the local filesystem.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to write any file that NiFi has access to in HDFS or the local filesystem."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.ACCESS_KEYTAB,
|
||||
explanation = "Provides operator the ability to make use of any keytab and principal on the local filesystem that NiFi has access to."),
|
||||
}
|
||||
)
|
||||
public class PutParquet extends AbstractPutHDFSRecord {
|
||||
|
||||
public static final PropertyDescriptor ROW_GROUP_SIZE = new PropertyDescriptor.Builder()
|
||||
|
@ -17,12 +17,14 @@
|
||||
package org.apache.nifi.lookup.script;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnDisabled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnEnabled;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.state.StateManager;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
@ -34,9 +36,9 @@ import org.apache.nifi.lookup.LookupService;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.processors.script.ScriptEngineConfigurator;
|
||||
import org.apache.nifi.script.AbstractScriptedControllerService;
|
||||
import org.apache.nifi.script.ScriptingComponentHelper;
|
||||
import org.apache.nifi.script.ScriptingComponentUtils;
|
||||
import org.apache.nifi.script.AbstractScriptedControllerService;
|
||||
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptException;
|
||||
@ -56,7 +58,13 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
*/
|
||||
@Tags({"lookup", "record", "script", "invoke", "groovy", "python", "jython", "jruby", "ruby", "javascript", "js", "lua", "luaj", "restricted"})
|
||||
@CapabilityDescription("Allows the user to provide a scripted LookupService instance in order to enrich records from an incoming flow file.")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ScriptedLookupService extends AbstractScriptedControllerService implements LookupService<Object> {
|
||||
|
||||
protected final AtomicReference<LookupService<Object>> lookupService = new AtomicReference<>();
|
||||
|
@ -20,17 +20,19 @@ package org.apache.nifi.processors.script;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.processor.AbstractSessionFactoryProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
@ -41,7 +43,6 @@ import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.script.ScriptingComponentHelper;
|
||||
import org.apache.nifi.script.ScriptingComponentUtils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
@ -49,6 +50,7 @@ import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -67,7 +69,13 @@ import java.util.Set;
|
||||
supportsExpressionLanguage = true,
|
||||
description = "Updates a script engine property specified by the Dynamic Property's key with the value "
|
||||
+ "specified by the Dynamic Property's value")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
@Stateful(scopes = {Scope.LOCAL, Scope.CLUSTER},
|
||||
description = "Scripts can store and retrieve state using the State Management APIs. Consult the State Manager section of the Developer's Guide for more details.")
|
||||
@SeeAlso({InvokeScriptedProcessor.class})
|
||||
|
@ -20,6 +20,7 @@ import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
@ -27,6 +28,7 @@ import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
@ -70,7 +72,13 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
@Stateful(scopes = {Scope.LOCAL, Scope.CLUSTER},
|
||||
description = "Scripts can store and retrieve state using the State Management APIs. Consult the State Manager section of the Developer's Guide for more details.")
|
||||
@SeeAlso({ExecuteScript.class})
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class InvokeScriptedProcessor extends AbstractSessionFactoryProcessor {
|
||||
|
||||
private final AtomicReference<Processor> processor = new AtomicReference<>();
|
||||
|
@ -17,9 +17,11 @@
|
||||
package org.apache.nifi.record.script;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnEnabled;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
@ -43,7 +45,13 @@ import java.util.Map;
|
||||
*/
|
||||
@Tags({"record", "recordFactory", "script", "invoke", "groovy", "python", "jython", "jruby", "ruby", "javascript", "js", "lua", "luaj", "restricted"})
|
||||
@CapabilityDescription("Allows the user to provide a scripted RecordReaderFactory instance in order to read/parse/generate records from an incoming flow file.")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ScriptedReader extends AbstractScriptedRecordFactory<RecordReaderFactory> implements RecordReaderFactory {
|
||||
|
||||
@OnEnabled
|
||||
|
@ -16,20 +16,12 @@
|
||||
*/
|
||||
package org.apache.nifi.record.script;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnEnabled;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
@ -39,12 +31,27 @@ import org.apache.nifi.serialization.RecordSetWriter;
|
||||
import org.apache.nifi.serialization.RecordSetWriterFactory;
|
||||
import org.apache.nifi.serialization.record.RecordSchema;
|
||||
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A RecordSetWriter implementation that allows the user to script the RecordWriter instance
|
||||
*/
|
||||
@Tags({"record", "writer", "script", "invoke", "groovy", "python", "jython", "jruby", "ruby", "javascript", "js", "lua", "luaj", "restricted"})
|
||||
@CapabilityDescription("Allows the user to provide a scripted RecordSetWriterFactory instance in order to write records to an outgoing flow file.")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ScriptedRecordSetWriter extends AbstractScriptedRecordFactory<RecordSetWriterFactory> implements RecordSetWriterFactory {
|
||||
|
||||
@Override
|
||||
|
@ -20,10 +20,12 @@ import com.yammer.metrics.core.VirtualMachineMetrics;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
@ -31,9 +33,9 @@ import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.processors.script.ScriptEngineConfigurator;
|
||||
import org.apache.nifi.script.ScriptingComponentHelper;
|
||||
import org.apache.nifi.reporting.AbstractReportingTask;
|
||||
import org.apache.nifi.reporting.ReportingContext;
|
||||
import org.apache.nifi.script.ScriptingComponentHelper;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
@ -61,7 +63,13 @@ import java.util.Map;
|
||||
supportsExpressionLanguage = true,
|
||||
description = "Updates a script engine property specified by the Dynamic Property's key with the value "
|
||||
+ "specified by the Dynamic Property's value")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ScriptedReportingTask extends AbstractReportingTask {
|
||||
|
||||
protected volatile ScriptingComponentHelper scriptingComponentHelper = new ScriptingComponentHelper();
|
||||
|
@ -17,6 +17,27 @@
|
||||
|
||||
package org.apache.nifi.reporting;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.configuration.DefaultSchedule;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.remote.Transaction;
|
||||
import org.apache.nifi.remote.TransferDirection;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
import javax.json.JsonArrayBuilder;
|
||||
import javax.json.JsonBuilderFactory;
|
||||
import javax.json.JsonObject;
|
||||
import javax.json.JsonObjectBuilder;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.DateFormat;
|
||||
@ -31,32 +52,18 @@ import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
import javax.json.JsonArrayBuilder;
|
||||
import javax.json.JsonBuilderFactory;
|
||||
import javax.json.JsonObject;
|
||||
import javax.json.JsonObjectBuilder;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.configuration.DefaultSchedule;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.remote.Transaction;
|
||||
import org.apache.nifi.remote.TransferDirection;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
|
||||
@Tags({"bulletin", "site", "site to site", "restricted"})
|
||||
@CapabilityDescription("Publishes Bulletin events using the Site To Site protocol. Note: only up to 5 bulletins are stored per component and up to "
|
||||
+ "10 bulletins at controller level for a duration of up to 5 minutes. If this reporting task is not scheduled frequently enough some bulletins "
|
||||
+ "may not be sent.")
|
||||
@Stateful(scopes = Scope.LOCAL, description = "Stores the Reporting Task's last bulletin ID so that on restart the task knows where it left off.")
|
||||
@Restricted("Provides operator the ability to send sensitive details contained in bulletin events to any external system.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXPORT_NIFI_DETAILS,
|
||||
explanation = "Provides operator the ability to send sensitive details contained in bulletin events to any external system.")
|
||||
}
|
||||
)
|
||||
@DefaultSchedule(strategy = SchedulingStrategy.TIMER_DRIVEN, period = "1 min")
|
||||
public class SiteToSiteBulletinReportingTask extends AbstractSiteToSiteReportingTask {
|
||||
|
||||
|
@ -19,6 +19,7 @@ package org.apache.nifi.reporting;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
@ -26,6 +27,7 @@ import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnUnscheduled;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.controller.status.ProcessGroupStatus;
|
||||
@ -64,7 +66,13 @@ import java.util.concurrent.TimeUnit;
|
||||
@Tags({"provenance", "lineage", "tracking", "site", "site to site", "restricted"})
|
||||
@CapabilityDescription("Publishes Provenance events using the Site To Site protocol.")
|
||||
@Stateful(scopes = Scope.LOCAL, description = "Stores the Reporting Task's last event Id so that on restart the task knows where it left off.")
|
||||
@Restricted("Provides operator the ability send sensitive details contained in Provenance events to any external system.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXPORT_NIFI_DETAILS,
|
||||
explanation = "Provides operator the ability to send sensitive details contained in Provenance events to any external system.")
|
||||
}
|
||||
)
|
||||
public class SiteToSiteProvenanceReportingTask extends AbstractSiteToSiteReportingTask {
|
||||
|
||||
static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
|
||||
|
@ -21,6 +21,7 @@ import org.apache.nifi.annotation.behavior.DynamicProperty;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
@ -28,6 +29,7 @@ import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnUnscheduled;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.Validator;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
@ -71,7 +73,13 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
+ "to be long-running, the Processor can output the partial data on a specified interval. When this option is used, the output is expected to be in textual "
|
||||
+ "format, as it typically does not make sense to split binary data on arbitrary time-based intervals.")
|
||||
@DynamicProperty(name = "An environment variable name", value = "An environment variable value", description = "These environment variables are passed to the process spawned by this Processor")
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
@WritesAttributes({
|
||||
@WritesAttribute(attribute = "command", description = "Executed command"),
|
||||
@WritesAttribute(attribute = "command.arguments", description = "Arguments of the command")
|
||||
|
@ -23,12 +23,14 @@ import org.apache.nifi.annotation.behavior.EventDriven;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.SupportsBatching;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.Validator;
|
||||
@ -138,7 +140,13 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
@WritesAttribute(attribute = "execution.command.args", description = "The semi-colon delimited list of arguments"),
|
||||
@WritesAttribute(attribute = "execution.status", description = "The exit status code returned from executing the command"),
|
||||
@WritesAttribute(attribute = "execution.error", description = "Any error messages returned from executing the command")})
|
||||
@Restricted("Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.EXECUTE_CODE,
|
||||
explanation = "Provides operator the ability to execute arbitrary code assuming all permissions that NiFi has.")
|
||||
}
|
||||
)
|
||||
public class ExecuteStreamCommand extends AbstractProcessor {
|
||||
|
||||
public static final Relationship ORIGINAL_RELATIONSHIP = new Relationship.Builder()
|
||||
|
@ -21,11 +21,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
@ -58,7 +60,16 @@ import java.util.concurrent.TimeUnit;
|
||||
@CapabilityDescription("Reads the contents of a file from disk and streams it into the contents of an incoming FlowFile. Once this is done, the file is optionally moved elsewhere or deleted "
|
||||
+ "to help keep the file system organized.")
|
||||
@SeeAlso({GetFile.class, PutFile.class, ListFile.class})
|
||||
@Restricted("Provides operator the ability to read from and delete any file that NiFi has access to.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to read from any file that NiFi has access to."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to.")
|
||||
}
|
||||
)
|
||||
public class FetchFile extends AbstractProcessor {
|
||||
static final AllowableValue COMPLETION_NONE = new AllowableValue("None", "None", "Leave the file as-is");
|
||||
static final AllowableValue COMPLETION_MOVE = new AllowableValue("Move File", "Move File", "Moves the file to the directory specified by the <Move Destination Directory> property");
|
||||
|
@ -19,6 +19,7 @@ package org.apache.nifi.processors.standard;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttributes;
|
||||
@ -27,6 +28,7 @@ import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
@ -93,7 +95,16 @@ import java.util.regex.Pattern;
|
||||
@WritesAttribute(attribute = "absolute.path", description = "The full/absolute path from where a file was picked up. The current 'path' "
|
||||
+ "attribute is still populated, but may be a relative path")})
|
||||
@SeeAlso({PutFile.class, FetchFile.class})
|
||||
@Restricted("Provides operator the ability to read from and delete any file that NiFi has access to.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to read from any file that NiFi has access to."),
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to delete any file that NiFi has access to.")
|
||||
}
|
||||
)
|
||||
public class GetFile extends AbstractProcessor {
|
||||
|
||||
public static final PropertyDescriptor DIRECTORY = new PropertyDescriptor.Builder()
|
||||
|
@ -21,11 +21,13 @@ import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.ReadsAttribute;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.SupportsBatching;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.SeeAlso;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
@ -63,7 +65,13 @@ import java.util.regex.Pattern;
|
||||
@CapabilityDescription("Writes the contents of a FlowFile to the local file system")
|
||||
@SeeAlso({FetchFile.class, GetFile.class})
|
||||
@ReadsAttribute(attribute = "filename", description = "The filename to use when writing the FlowFile to disk.")
|
||||
@Restricted("Provides operator the ability to write to any file that NiFi has access to.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.WRITE_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to write to any file that NiFi has access to.")
|
||||
}
|
||||
)
|
||||
public class PutFile extends AbstractProcessor {
|
||||
|
||||
public static final String REPLACE_RESOLUTION = "replace";
|
||||
|
@ -16,6 +16,39 @@
|
||||
*/
|
||||
package org.apache.nifi.processors.standard;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Restriction;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.behavior.TriggerSerially;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.annotation.notification.OnPrimaryNodeStateChange;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.RequiredPermission;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.components.state.StateMap;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.AbstractProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.io.OutputStreamCallback;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.stream.io.NullOutputStream;
|
||||
import org.apache.nifi.stream.io.StreamUtils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
@ -47,37 +80,6 @@ import java.util.zip.CRC32;
|
||||
import java.util.zip.CheckedInputStream;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.behavior.TriggerSerially;
|
||||
import org.apache.nifi.annotation.behavior.WritesAttribute;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.annotation.notification.OnPrimaryNodeStateChange;
|
||||
import org.apache.nifi.components.AllowableValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.components.state.Scope;
|
||||
import org.apache.nifi.components.state.StateMap;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||
import org.apache.nifi.processor.AbstractProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.processor.io.OutputStreamCallback;
|
||||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.stream.io.NullOutputStream;
|
||||
import org.apache.nifi.stream.io.StreamUtils;
|
||||
|
||||
// note: it is important that this Processor is not marked as @SupportsBatching because the session commits must complete before persisting state locally; otherwise, data loss may occur
|
||||
@TriggerSerially
|
||||
@InputRequirement(Requirement.INPUT_FORBIDDEN)
|
||||
@ -91,7 +93,13 @@ import org.apache.nifi.stream.io.StreamUtils;
|
||||
@Stateful(scopes = {Scope.LOCAL, Scope.CLUSTER}, description = "Stores state about where in the Tailed File it left off so that on restart it does not have to duplicate data. "
|
||||
+ "State is stored either local or clustered depend on the <File Location> property.")
|
||||
@WritesAttribute(attribute = "tailfile.original.path", description = "Path of the original file the flow file comes from.")
|
||||
@Restricted("Provides operator the ability to read from any file that NiFi has access to.")
|
||||
@Restricted(
|
||||
restrictions = {
|
||||
@Restriction(
|
||||
requiredPermission = RequiredPermission.READ_FILESYSTEM,
|
||||
explanation = "Provides operator the ability to read from any file that NiFi has access to.")
|
||||
}
|
||||
)
|
||||
public class TailFile extends AbstractProcessor {
|
||||
|
||||
static final String MAP_PREFIX = "file.";
|
||||
|
Loading…
x
Reference in New Issue
Block a user