mirror of https://github.com/apache/nifi.git
NIFI-1950 Updating FileAuthorizer to convert access controls from input and output ports during legacy conversion. This closes #702.
This commit is contained in:
parent
b082858595
commit
3e9867d5da
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.authorization;
|
package org.apache.nifi.authorization;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.nifi.authorization.annotation.AuthorizerContext;
|
import org.apache.nifi.authorization.annotation.AuthorizerContext;
|
||||||
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
|
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
|
||||||
|
@ -26,14 +25,14 @@ import org.apache.nifi.authorization.file.generated.Groups;
|
||||||
import org.apache.nifi.authorization.file.generated.Policies;
|
import org.apache.nifi.authorization.file.generated.Policies;
|
||||||
import org.apache.nifi.authorization.file.generated.Policy;
|
import org.apache.nifi.authorization.file.generated.Policy;
|
||||||
import org.apache.nifi.authorization.file.generated.Users;
|
import org.apache.nifi.authorization.file.generated.Users;
|
||||||
|
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||||
import org.apache.nifi.authorization.resource.ResourceType;
|
import org.apache.nifi.authorization.resource.ResourceType;
|
||||||
import org.apache.nifi.components.PropertyValue;
|
import org.apache.nifi.components.PropertyValue;
|
||||||
import org.apache.nifi.util.NiFiProperties;
|
import org.apache.nifi.util.NiFiProperties;
|
||||||
import org.apache.nifi.util.file.FileUtils;
|
import org.apache.nifi.util.file.FileUtils;
|
||||||
|
import org.apache.nifi.web.api.dto.PortDTO;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
|
@ -42,20 +41,12 @@ import javax.xml.bind.JAXBElement;
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
import javax.xml.bind.Marshaller;
|
import javax.xml.bind.Marshaller;
|
||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
import javax.xml.validation.Schema;
|
import javax.xml.validation.Schema;
|
||||||
import javax.xml.validation.SchemaFactory;
|
import javax.xml.validation.SchemaFactory;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -68,7 +59,6 @@ import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides authorizes requests to resources using policies persisted in a file.
|
* Provides authorizes requests to resources using policies persisted in a file.
|
||||||
|
@ -83,8 +73,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
private static final String USERS_XSD = "/users.xsd";
|
private static final String USERS_XSD = "/users.xsd";
|
||||||
private static final String JAXB_USERS_PATH = "org.apache.nifi.user.generated";
|
private static final String JAXB_USERS_PATH = "org.apache.nifi.user.generated";
|
||||||
|
|
||||||
private static final String FLOW_XSD = "/FlowConfiguration.xsd";
|
|
||||||
|
|
||||||
private static final JAXBContext JAXB_AUTHORIZATIONS_CONTEXT = initializeJaxbContext(JAXB_AUTHORIZATIONS_PATH);
|
private static final JAXBContext JAXB_AUTHORIZATIONS_CONTEXT = initializeJaxbContext(JAXB_AUTHORIZATIONS_PATH);
|
||||||
private static final JAXBContext JAXB_USERS_CONTEXT = initializeJaxbContext(JAXB_USERS_PATH);
|
private static final JAXBContext JAXB_USERS_CONTEXT = initializeJaxbContext(JAXB_USERS_PATH);
|
||||||
|
|
||||||
|
@ -107,7 +95,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
static final String PROP_LEGACY_AUTHORIZED_USERS_FILE = "Legacy Authorized Users File";
|
static final String PROP_LEGACY_AUTHORIZED_USERS_FILE = "Legacy Authorized Users File";
|
||||||
static final Pattern NODE_IDENTITY_PATTERN = Pattern.compile("Node Identity \\S+");
|
static final Pattern NODE_IDENTITY_PATTERN = Pattern.compile("Node Identity \\S+");
|
||||||
|
|
||||||
private Schema flowSchema;
|
|
||||||
private Schema usersSchema;
|
private Schema usersSchema;
|
||||||
private Schema authorizationsSchema;
|
private Schema authorizationsSchema;
|
||||||
private SchemaFactory schemaFactory;
|
private SchemaFactory schemaFactory;
|
||||||
|
@ -118,6 +105,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
private String initialAdminIdentity;
|
private String initialAdminIdentity;
|
||||||
private String legacyAuthorizedUsersFile;
|
private String legacyAuthorizedUsersFile;
|
||||||
private Set<String> nodeIdentities;
|
private Set<String> nodeIdentities;
|
||||||
|
private List<PortDTO> ports = new ArrayList<>();
|
||||||
|
|
||||||
private final AtomicReference<AuthorizationsHolder> authorizationsHolder = new AtomicReference<>();
|
private final AtomicReference<AuthorizationsHolder> authorizationsHolder = new AtomicReference<>();
|
||||||
|
|
||||||
|
@ -127,7 +115,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
authorizationsSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(AUTHORIZATIONS_XSD));
|
authorizationsSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(AUTHORIZATIONS_XSD));
|
||||||
usersSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(USERS_XSD));
|
usersSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(USERS_XSD));
|
||||||
flowSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(FLOW_XSD));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AuthorizerCreationException(e);
|
throw new AuthorizerCreationException(e);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +187,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
|
|
||||||
logger.info(String.format("Authorizations file loaded at %s", new Date().toString()));
|
logger.info(String.format("Authorizations file loaded at %s", new Date().toString()));
|
||||||
|
|
||||||
} catch (IOException | AuthorizerCreationException | JAXBException | IllegalStateException e) {
|
} catch (IOException | AuthorizerCreationException | JAXBException | IllegalStateException | SAXException e) {
|
||||||
throw new AuthorizerCreationException(e);
|
throw new AuthorizerCreationException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +199,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
* @throws IOException Unable to sync file with restore
|
* @throws IOException Unable to sync file with restore
|
||||||
* @throws IllegalStateException Unable to sync file with restore
|
* @throws IllegalStateException Unable to sync file with restore
|
||||||
*/
|
*/
|
||||||
private synchronized void load() throws JAXBException, IOException, IllegalStateException {
|
private synchronized void load() throws JAXBException, IOException, IllegalStateException, SAXException {
|
||||||
// attempt to unmarshal
|
// attempt to unmarshal
|
||||||
final Unmarshaller unmarshaller = JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
|
final Unmarshaller unmarshaller = JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
|
||||||
unmarshaller.setSchema(authorizationsSchema);
|
unmarshaller.setSchema(authorizationsSchema);
|
||||||
|
@ -237,8 +224,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
|
|
||||||
// if we are starting fresh then we might need to populate an initial admin or convert legacy users
|
// if we are starting fresh then we might need to populate an initial admin or convert legacy users
|
||||||
if (emptyAuthorizations) {
|
if (emptyAuthorizations) {
|
||||||
// try to extract the root group id from the flow configuration file specified in nifi.properties
|
parseFlow();
|
||||||
rootGroupId = getRootGroupId();
|
|
||||||
|
|
||||||
if (hasInitialAdminIdentity && hasLegacyAuthorizedUsers) {
|
if (hasInitialAdminIdentity && hasLegacyAuthorizedUsers) {
|
||||||
throw new AuthorizerCreationException("Cannot provide an Initial Admin Identity and a Legacy Authorized Users File");
|
throw new AuthorizerCreationException("Cannot provide an Initial Admin Identity and a Legacy Authorized Users File");
|
||||||
|
@ -260,68 +246,17 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the root group id from the flow configuration file provided in nifi.properties.
|
* Try to parse the flow configuration file to extract the root group id and port information.
|
||||||
*
|
*
|
||||||
* @return the root group id, or null if the files doesn't exist, was empty, or could not be parsed
|
* @throws SAXException if an error occurs creating the schema
|
||||||
*/
|
*/
|
||||||
private String getRootGroupId() {
|
private void parseFlow() throws SAXException {
|
||||||
final File flowFile = properties.getFlowConfigurationFile();
|
final FlowParser flowParser = new FlowParser();
|
||||||
if (flowFile == null) {
|
final FlowInfo flowInfo = flowParser.parse(properties.getFlowConfigurationFile());
|
||||||
logger.debug("Flow Configuration file was null");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the flow doesn't exist or is 0 bytes, then return null
|
if (flowInfo != null) {
|
||||||
final Path flowPath = flowFile.toPath();
|
rootGroupId = flowInfo.getRootGroupId();
|
||||||
try {
|
ports = flowInfo.getPorts() == null ? new ArrayList<>() : flowInfo.getPorts();
|
||||||
if (!Files.exists(flowPath) || Files.size(flowPath) == 0) {
|
|
||||||
logger.debug("Flow Configuration does not exist or was empty");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.debug("An error occurred determining the size of the Flow Configuration file");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise create the appropriate input streams to read the file
|
|
||||||
try (final InputStream in = Files.newInputStream(flowPath, StandardOpenOption.READ);
|
|
||||||
final InputStream gzipIn = new GZIPInputStream(in)) {
|
|
||||||
|
|
||||||
final byte[] flowBytes = IOUtils.toByteArray(gzipIn);
|
|
||||||
if (flowBytes == null || flowBytes.length == 0) {
|
|
||||||
logger.debug("Could not extract root group id because Flow Configuration File was empty");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create validating document builder
|
|
||||||
final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
docFactory.setNamespaceAware(true);
|
|
||||||
docFactory.setSchema(flowSchema);
|
|
||||||
|
|
||||||
// parse the flow
|
|
||||||
final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
|
||||||
final Document document = docBuilder.parse(new ByteArrayInputStream(flowBytes));
|
|
||||||
|
|
||||||
// extract the root group id
|
|
||||||
final Element rootElement = document.getDocumentElement();
|
|
||||||
|
|
||||||
final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
|
|
||||||
if (rootGroupElement == null) {
|
|
||||||
logger.debug("rootGroup element not found in Flow Configuration file");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Element rootGroupIdElement = (Element) rootGroupElement.getElementsByTagName("id").item(0);
|
|
||||||
if (rootGroupIdElement == null) {
|
|
||||||
logger.debug("id element not found under rootGroup in Flow Configuration file");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rootGroupIdElement.getTextContent();
|
|
||||||
|
|
||||||
} catch (final SAXException | ParserConfigurationException | IOException ex) {
|
|
||||||
logger.error("Unable to find root group id in {} due to {}", new Object[] { flowPath.toAbsolutePath(), ex });
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +287,10 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
// grant the user read/write access to the /policies resource
|
// grant the user read/write access to the /policies resource
|
||||||
addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), READ_CODE);
|
addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), READ_CODE);
|
||||||
addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), WRITE_CODE);
|
addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), WRITE_CODE);
|
||||||
|
|
||||||
|
// grant the user read/write access to the /controller resource
|
||||||
|
addAccessPolicy(authorizations, ResourceType.Controller.getValue(), adminUser.getIdentifier(), READ_CODE);
|
||||||
|
addAccessPolicy(authorizations, ResourceType.Controller.getValue(), adminUser.getIdentifier(), WRITE_CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -428,8 +367,8 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
|
|
||||||
for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
|
for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
|
||||||
// create the identifier of the new user based on the DN
|
// create the identifier of the new user based on the DN
|
||||||
String legacyUserDn = legacyUser.getDn();
|
final String legacyUserDn = legacyUser.getDn();
|
||||||
String userIdentifier = UUID.nameUUIDFromBytes(legacyUserDn.getBytes(StandardCharsets.UTF_8)).toString();
|
final String userIdentifier = UUID.nameUUIDFromBytes(legacyUserDn.getBytes(StandardCharsets.UTF_8)).toString();
|
||||||
|
|
||||||
// create the new User and add it to the list of users
|
// create the new User and add it to the list of users
|
||||||
org.apache.nifi.authorization.file.generated.User user = new org.apache.nifi.authorization.file.generated.User();
|
org.apache.nifi.authorization.file.generated.User user = new org.apache.nifi.authorization.file.generated.User();
|
||||||
|
@ -459,29 +398,128 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
|
||||||
roleAccessPolicy.getResource(),
|
roleAccessPolicy.getResource(),
|
||||||
roleAccessPolicy.getAction());
|
roleAccessPolicy.getAction());
|
||||||
|
|
||||||
// determine if the user already exists in the policy
|
// add the user to the policy if it doesn't exist
|
||||||
boolean userExists = false;
|
addUserToPolicy(userIdentifier, policy);
|
||||||
for (Policy.User policyUser : policy.getUser()) {
|
|
||||||
if (policyUser.getIdentifier().equals(userIdentifier)) {
|
|
||||||
userExists = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the user to the policy if doesn't already exist
|
|
||||||
if (!userExists) {
|
|
||||||
Policy.User policyUser = new Policy.User();
|
|
||||||
policyUser.setIdentifier(userIdentifier);
|
|
||||||
policy.getUser().add(policyUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert any access controls on ports to the appropriate policies
|
||||||
|
for (PortDTO portDTO : ports) {
|
||||||
|
final boolean isInputPort = portDTO.getType() != null && portDTO.getType().equals("inputPort");
|
||||||
|
final Resource resource = ResourceFactory.getDataTransferResource(isInputPort, portDTO.getId(), portDTO.getName());
|
||||||
|
|
||||||
|
if (portDTO.getUserAccessControl() != null) {
|
||||||
|
for (String userAccessControl : portDTO.getUserAccessControl()) {
|
||||||
|
// find a user where the identity is the userAccessControl
|
||||||
|
org.apache.nifi.authorization.file.generated.User foundUser = null;
|
||||||
|
for (org.apache.nifi.authorization.file.generated.User jaxbUser : authorizations.getUsers().getUser()) {
|
||||||
|
if (jaxbUser.getIdentity().equals(userAccessControl)) {
|
||||||
|
foundUser = jaxbUser;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// couldn't find the user matching the access control so log a warning and skip
|
||||||
|
if (foundUser == null) {
|
||||||
|
logger.warn("Found port with user access control for {} but no user exists with this identity, skipping...",
|
||||||
|
new Object[] {userAccessControl});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we found the user so create the appropriate policy and add the user to it
|
||||||
|
Policy policy = getOrCreatePolicy(
|
||||||
|
allPolicies,
|
||||||
|
seedIdentity,
|
||||||
|
resource.getIdentifier(),
|
||||||
|
WRITE_CODE);
|
||||||
|
|
||||||
|
addUserToPolicy(foundUser.getIdentifier(), policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (portDTO.getGroupAccessControl() != null) {
|
||||||
|
for (String groupAccessControl : portDTO.getGroupAccessControl()) {
|
||||||
|
// find a group where the name is the groupAccessControl
|
||||||
|
org.apache.nifi.authorization.file.generated.Group foundGroup = null;
|
||||||
|
for (org.apache.nifi.authorization.file.generated.Group jaxbGroup : authorizations.getGroups().getGroup()) {
|
||||||
|
if (jaxbGroup.getName().equals(groupAccessControl)) {
|
||||||
|
foundGroup = jaxbGroup;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// couldn't find the group matching the access control so log a warning and skip
|
||||||
|
if (foundGroup == null) {
|
||||||
|
logger.warn("Found port with group access control for {} but no group exists with this name, skipping...",
|
||||||
|
new Object[] {groupAccessControl});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we found the group so create the appropriate policy and add all the users to it
|
||||||
|
Policy policy = getOrCreatePolicy(
|
||||||
|
allPolicies,
|
||||||
|
seedIdentity,
|
||||||
|
resource.getIdentifier(),
|
||||||
|
WRITE_CODE);
|
||||||
|
|
||||||
|
addGroupToPolicy(foundGroup.getIdentifier(), policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
authorizations.getPolicies().getPolicy().addAll(allPolicies);
|
authorizations.getPolicies().getPolicy().addAll(allPolicies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given user identifier to the policy if it doesn't already exist.
|
||||||
|
*
|
||||||
|
* @param userIdentifier a user identifier
|
||||||
|
* @param policy a policy to add the user to
|
||||||
|
*/
|
||||||
|
private void addUserToPolicy(final String userIdentifier, final Policy policy) {
|
||||||
|
// determine if the user already exists in the policy
|
||||||
|
boolean userExists = false;
|
||||||
|
for (Policy.User policyUser : policy.getUser()) {
|
||||||
|
if (policyUser.getIdentifier().equals(userIdentifier)) {
|
||||||
|
userExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the user to the policy if doesn't already exist
|
||||||
|
if (!userExists) {
|
||||||
|
Policy.User policyUser = new Policy.User();
|
||||||
|
policyUser.setIdentifier(userIdentifier);
|
||||||
|
policy.getUser().add(policyUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given group identifier to the policy if it doesn't already exist.
|
||||||
|
*
|
||||||
|
* @param groupIdentifier a group identifier
|
||||||
|
* @param policy a policy to add the user to
|
||||||
|
*/
|
||||||
|
private void addGroupToPolicy(final String groupIdentifier, final Policy policy) {
|
||||||
|
// determine if the group already exists in the policy
|
||||||
|
boolean groupExists = false;
|
||||||
|
for (Policy.Group policyGroup : policy.getGroup()) {
|
||||||
|
if (policyGroup.getIdentifier().equals(groupIdentifier)) {
|
||||||
|
groupExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the group to the policy if doesn't already exist
|
||||||
|
if (!groupExists) {
|
||||||
|
Policy.Group policyGroup = new Policy.Group();
|
||||||
|
policyGroup.setIdentifier(groupIdentifier);
|
||||||
|
policy.getGroup().add(policyGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the Group with the given name, or creates a new one and adds it to Authorizations.
|
* Finds the Group with the given name, or creates a new one and adds it to Authorizations.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.apache.nifi.web.api.dto.PortDTO;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FlowInfo {
|
||||||
|
|
||||||
|
private final String rootGroupId;
|
||||||
|
|
||||||
|
private final List<PortDTO> ports;
|
||||||
|
|
||||||
|
public FlowInfo(final String rootGroupId, final List<PortDTO> ports) {
|
||||||
|
this.rootGroupId = rootGroupId;
|
||||||
|
this.ports = (ports == null ? Collections.unmodifiableList(Collections.EMPTY_LIST) :
|
||||||
|
Collections.unmodifiableList(new ArrayList<>(ports)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRootGroupId() {
|
||||||
|
return rootGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PortDTO> getPorts() {
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
|
||||||
|
import org.apache.nifi.web.api.dto.PortDTO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a flow and returns the root group id and root group ports.
|
||||||
|
*/
|
||||||
|
public class FlowParser {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FlowParser.class);
|
||||||
|
|
||||||
|
private static final String FLOW_XSD = "/FlowConfiguration.xsd";
|
||||||
|
|
||||||
|
private Schema flowSchema;
|
||||||
|
private SchemaFactory schemaFactory;
|
||||||
|
|
||||||
|
public FlowParser() throws SAXException {
|
||||||
|
schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
|
flowSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(FLOW_XSD));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the root group id from the flow configuration file provided in nifi.properties, and extracts
|
||||||
|
* the root group input ports and output ports, and their access controls.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public FlowInfo parse(final File flowConfigurationFile) {
|
||||||
|
if (flowConfigurationFile == null) {
|
||||||
|
logger.debug("Flow Configuration file was null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the flow doesn't exist or is 0 bytes, then return null
|
||||||
|
final Path flowPath = flowConfigurationFile.toPath();
|
||||||
|
try {
|
||||||
|
if (!Files.exists(flowPath) || Files.size(flowPath) == 0) {
|
||||||
|
logger.warn("Flow Configuration does not exist or was empty");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("An error occurred determining the size of the Flow Configuration file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise create the appropriate input streams to read the file
|
||||||
|
try (final InputStream in = Files.newInputStream(flowPath, StandardOpenOption.READ);
|
||||||
|
final InputStream gzipIn = new GZIPInputStream(in)) {
|
||||||
|
|
||||||
|
final byte[] flowBytes = IOUtils.toByteArray(gzipIn);
|
||||||
|
if (flowBytes == null || flowBytes.length == 0) {
|
||||||
|
logger.warn("Could not extract root group id because Flow Configuration File was empty");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create validating document builder
|
||||||
|
final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
docFactory.setNamespaceAware(true);
|
||||||
|
docFactory.setSchema(flowSchema);
|
||||||
|
|
||||||
|
// parse the flow
|
||||||
|
final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||||
|
final Document document = docBuilder.parse(new ByteArrayInputStream(flowBytes));
|
||||||
|
|
||||||
|
// extract the root group id
|
||||||
|
final Element rootElement = document.getDocumentElement();
|
||||||
|
|
||||||
|
final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
|
||||||
|
if (rootGroupElement == null) {
|
||||||
|
logger.warn("rootGroup element not found in Flow Configuration file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Element rootGroupIdElement = (Element) rootGroupElement.getElementsByTagName("id").item(0);
|
||||||
|
if (rootGroupIdElement == null) {
|
||||||
|
logger.warn("id element not found under rootGroup in Flow Configuration file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String rootGroupId = rootGroupIdElement.getTextContent();
|
||||||
|
|
||||||
|
final List<PortDTO> ports = new ArrayList<>();
|
||||||
|
ports.addAll(getPorts(rootGroupElement, "inputPort"));
|
||||||
|
ports.addAll(getPorts(rootGroupElement, "outputPort"));
|
||||||
|
|
||||||
|
return new FlowInfo(rootGroupId, ports);
|
||||||
|
|
||||||
|
} catch (final SAXException | ParserConfigurationException | IOException ex) {
|
||||||
|
logger.error("Unable to parse flow {} due to {}", new Object[] { flowPath.toAbsolutePath(), ex });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ports that are direct children of the given element.
|
||||||
|
*
|
||||||
|
* @param element the element containing ports
|
||||||
|
* @param type the type of port to find (inputPort or outputPort)
|
||||||
|
* @return a list of PortDTOs representing the found ports
|
||||||
|
*/
|
||||||
|
private List<PortDTO> getPorts(final Element element, final String type) {
|
||||||
|
final List<PortDTO> ports = new ArrayList<>();
|
||||||
|
|
||||||
|
// add input ports
|
||||||
|
final List<Element> portNodeList = getChildrenByTagName(element, type);
|
||||||
|
for (final Element portElement : portNodeList) {
|
||||||
|
final PortDTO portDTO = FlowFromDOMFactory.getPort(portElement);
|
||||||
|
portDTO.setType(type);
|
||||||
|
ports.add(portDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds child elements with the given tagName.
|
||||||
|
*
|
||||||
|
* @param element the parent element
|
||||||
|
* @param tagName the child element name to find
|
||||||
|
* @return a list of matching child elements
|
||||||
|
*/
|
||||||
|
private static List<Element> getChildrenByTagName(final Element element, final String tagName) {
|
||||||
|
final List<Element> matches = new ArrayList<>();
|
||||||
|
final NodeList nodeList = element.getChildNodes();
|
||||||
|
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||||
|
final Node node = nodeList.item(i);
|
||||||
|
if (!(node instanceof Element)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Element child = (Element) nodeList.item(i);
|
||||||
|
if (child.getNodeName().equals(tagName)) {
|
||||||
|
matches.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -111,6 +111,7 @@ public class FileAuthorizerTest {
|
||||||
private File primary;
|
private File primary;
|
||||||
private File restore;
|
private File restore;
|
||||||
private File flow;
|
private File flow;
|
||||||
|
private File flowNoPorts;
|
||||||
|
|
||||||
private AuthorizerConfigurationContext configurationContext;
|
private AuthorizerConfigurationContext configurationContext;
|
||||||
|
|
||||||
|
@ -127,6 +128,9 @@ public class FileAuthorizerTest {
|
||||||
flow = new File("src/test/resources/flow.xml.gz");
|
flow = new File("src/test/resources/flow.xml.gz");
|
||||||
FileUtils.ensureDirectoryExistAndCanAccess(flow.getParentFile());
|
FileUtils.ensureDirectoryExistAndCanAccess(flow.getParentFile());
|
||||||
|
|
||||||
|
flowNoPorts = new File("src/test/resources/flow-no-ports.xml.gz");
|
||||||
|
FileUtils.ensureDirectoryExistAndCanAccess(flowNoPorts.getParentFile());
|
||||||
|
|
||||||
properties = mock(NiFiProperties.class);
|
properties = mock(NiFiProperties.class);
|
||||||
when(properties.getRestoreDirectory()).thenReturn(restore.getParentFile());
|
when(properties.getRestoreDirectory()).thenReturn(restore.getParentFile());
|
||||||
when(properties.getFlowConfigurationFile()).thenReturn(flow);
|
when(properties.getFlowConfigurationFile()).thenReturn(flow);
|
||||||
|
@ -165,6 +169,29 @@ public class FileAuthorizerTest {
|
||||||
assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.WRITE));
|
assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnConfiguredWhenLegacyUsersFileProvidedAndFlowHasNoPorts() throws Exception {
|
||||||
|
properties = mock(NiFiProperties.class);
|
||||||
|
when(properties.getRestoreDirectory()).thenReturn(restore.getParentFile());
|
||||||
|
when(properties.getFlowConfigurationFile()).thenReturn(flowNoPorts);
|
||||||
|
|
||||||
|
when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
|
||||||
|
.thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null));
|
||||||
|
|
||||||
|
writeAuthorizationsFile(primary, EMPTY_AUTHORIZATIONS_CONCISE);
|
||||||
|
authorizer.onConfigured(configurationContext);
|
||||||
|
|
||||||
|
boolean foundDataTransferPolicy = false;
|
||||||
|
for (AccessPolicy policy : authorizer.getAccessPolicies()) {
|
||||||
|
if (policy.getResource().contains(ResourceType.DataTransfer.name())) {
|
||||||
|
foundDataTransferPolicy = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(foundDataTransferPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnConfiguredWhenLegacyUsersFileProvided() throws Exception {
|
public void testOnConfiguredWhenLegacyUsersFileProvided() throws Exception {
|
||||||
when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
|
when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
|
||||||
|
@ -198,7 +225,8 @@ public class FileAuthorizerTest {
|
||||||
// verify one group got created
|
// verify one group got created
|
||||||
final Set<Group> groups = authorizer.getGroups();
|
final Set<Group> groups = authorizer.getGroups();
|
||||||
assertEquals(1, groups.size());
|
assertEquals(1, groups.size());
|
||||||
assertEquals("group1", groups.iterator().next().getName());
|
final Group group1 = groups.iterator().next();
|
||||||
|
assertEquals("group1", group1.getName());
|
||||||
|
|
||||||
// verify more than one policy got created
|
// verify more than one policy got created
|
||||||
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
||||||
|
@ -238,7 +266,7 @@ public class FileAuthorizerTest {
|
||||||
|
|
||||||
// verify user4's policies
|
// verify user4's policies
|
||||||
final Map<String,Set<RequestAction>> user4Policies = getResourceActions(policies, user4);
|
final Map<String,Set<RequestAction>> user4Policies = getResourceActions(policies, user4);
|
||||||
assertEquals(5, user4Policies.size());
|
assertEquals(6, user4Policies.size());
|
||||||
|
|
||||||
assertTrue(user4Policies.containsKey(ResourceType.Flow.getValue()));
|
assertTrue(user4Policies.containsKey(ResourceType.Flow.getValue()));
|
||||||
assertEquals(1, user4Policies.get(ResourceType.Flow.getValue()).size());
|
assertEquals(1, user4Policies.get(ResourceType.Flow.getValue()).size());
|
||||||
|
@ -266,11 +294,25 @@ public class FileAuthorizerTest {
|
||||||
|
|
||||||
// verify user6's policies
|
// verify user6's policies
|
||||||
final Map<String,Set<RequestAction>> user6Policies = getResourceActions(policies, user6);
|
final Map<String,Set<RequestAction>> user6Policies = getResourceActions(policies, user6);
|
||||||
assertEquals(2, user6Policies.size());
|
assertEquals(3, user6Policies.size());
|
||||||
|
|
||||||
assertTrue(user6Policies.containsKey(ResourceType.SiteToSite.getValue()));
|
assertTrue(user6Policies.containsKey(ResourceType.SiteToSite.getValue()));
|
||||||
assertEquals(2, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
|
assertEquals(2, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
|
||||||
assertTrue(user6Policies.get(ResourceType.SiteToSite.getValue()).contains(RequestAction.WRITE));
|
assertTrue(user6Policies.get(ResourceType.SiteToSite.getValue()).contains(RequestAction.WRITE));
|
||||||
|
|
||||||
|
final Resource inputPortResource = ResourceFactory.getDataTransferResource(true, "2f7d1606-b090-4be7-a592-a5b70fb55531", "TCP Input");
|
||||||
|
final AccessPolicy inputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(inputPortResource.getIdentifier(), RequestAction.WRITE);
|
||||||
|
assertNotNull(inputPortPolicy);
|
||||||
|
assertEquals(1, inputPortPolicy.getUsers().size());
|
||||||
|
assertTrue(inputPortPolicy.getUsers().contains(user6.getIdentifier()));
|
||||||
|
assertEquals(1, inputPortPolicy.getGroups().size());
|
||||||
|
assertTrue(inputPortPolicy.getGroups().contains(group1.getIdentifier()));
|
||||||
|
|
||||||
|
final Resource outputPortResource = ResourceFactory.getDataTransferResource(false, "2f7d1606-b090-4be7-a592-a5b70fb55532", "TCP Output");
|
||||||
|
final AccessPolicy outputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(outputPortResource.getIdentifier(), RequestAction.WRITE);
|
||||||
|
assertNotNull(outputPortPolicy);
|
||||||
|
assertEquals(1, outputPortPolicy.getUsers().size());
|
||||||
|
assertTrue(outputPortPolicy.getUsers().contains(user4.getIdentifier()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String,Set<RequestAction>> getResourceActions(final Set<AccessPolicy> policies, final User user) {
|
private Map<String,Set<RequestAction>> getResourceActions(final Set<AccessPolicy> policies, final User user) {
|
||||||
|
@ -342,7 +384,7 @@ public class FileAuthorizerTest {
|
||||||
assertEquals(adminIdentity, adminUser.getIdentity());
|
assertEquals(adminIdentity, adminUser.getIdentity());
|
||||||
|
|
||||||
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
||||||
assertEquals(7, policies.size());
|
assertEquals(9, policies.size());
|
||||||
|
|
||||||
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
||||||
|
|
||||||
|
@ -379,7 +421,7 @@ public class FileAuthorizerTest {
|
||||||
assertEquals(adminIdentity, adminUser.getIdentity());
|
assertEquals(adminIdentity, adminUser.getIdentity());
|
||||||
|
|
||||||
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
||||||
assertEquals(5, policies.size());
|
assertEquals(7, policies.size());
|
||||||
|
|
||||||
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
||||||
|
|
||||||
|
@ -416,7 +458,7 @@ public class FileAuthorizerTest {
|
||||||
assertEquals(adminIdentity, adminUser.getIdentity());
|
assertEquals(adminIdentity, adminUser.getIdentity());
|
||||||
|
|
||||||
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
|
||||||
assertEquals(5, policies.size());
|
assertEquals(7, policies.size());
|
||||||
|
|
||||||
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
- Node Identity [unique key] - The identity of a NiFi cluster node. When clustered, a property for each node
|
- Node Identity [unique key] - The identity of a NiFi cluster node. When clustered, a property for each node
|
||||||
should be defined, so that every node knows about every other node. If not clustered these properties can be ignored.
|
should be defined, so that every node knows about every other node. If not clustered these properties can be ignored.
|
||||||
|
The name of each property must be unique, for example for a three node cluster:
|
||||||
|
"Node Identity A", "Node Identity B", "Node Identity C" or "Node Identity 1", "Node Identity 2", "Node Identity 3"
|
||||||
-->
|
-->
|
||||||
<authorizer>
|
<authorizer>
|
||||||
<identifier>file-provider</identifier>
|
<identifier>file-provider</identifier>
|
||||||
|
@ -44,7 +46,8 @@
|
||||||
<property name="Authorizations File">./conf/authorizations.xml</property>
|
<property name="Authorizations File">./conf/authorizations.xml</property>
|
||||||
<property name="Initial Admin Identity"></property>
|
<property name="Initial Admin Identity"></property>
|
||||||
<property name="Legacy Authorized Users File"></property>
|
<property name="Legacy Authorized Users File"></property>
|
||||||
<!--
|
|
||||||
|
<!-- Provide the identity (typically a DN) of each node when clustered, see above description of Node Identity.
|
||||||
<property name="Node Identity 1"></property>
|
<property name="Node Identity 1"></property>
|
||||||
<property name="Node Identity 2"></property>
|
<property name="Node Identity 2"></property>
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.nifi.authorization.AuthorizationResult.Result;
|
||||||
import org.apache.nifi.authorization.Authorizer;
|
import org.apache.nifi.authorization.Authorizer;
|
||||||
import org.apache.nifi.authorization.RequestAction;
|
import org.apache.nifi.authorization.RequestAction;
|
||||||
import org.apache.nifi.authorization.Resource;
|
import org.apache.nifi.authorization.Resource;
|
||||||
|
import org.apache.nifi.authorization.UserContextKeys;
|
||||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||||
import org.apache.nifi.authorization.resource.ResourceType;
|
import org.apache.nifi.authorization.resource.ResourceType;
|
||||||
import org.apache.nifi.authorization.user.NiFiUser;
|
import org.apache.nifi.authorization.user.NiFiUser;
|
||||||
|
@ -77,6 +78,8 @@ import javax.ws.rs.core.UriInfo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
import static org.apache.commons.lang3.StringUtils.isEmpty;
|
||||||
import static org.apache.nifi.remote.protocol.HandshakeProperty.BATCH_COUNT;
|
import static org.apache.nifi.remote.protocol.HandshakeProperty.BATCH_COUNT;
|
||||||
|
@ -125,6 +128,14 @@ public class DataTransferResource extends ApplicationResource {
|
||||||
throw new IllegalArgumentException("The resource must be an Input or Output Port.");
|
throw new IllegalArgumentException("The resource must be an Input or Output Port.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Map<String,String> userContext;
|
||||||
|
if (user.getClientAddress() != null && !user.getClientAddress().trim().isEmpty()) {
|
||||||
|
userContext = new HashMap<>();
|
||||||
|
userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
|
||||||
|
} else {
|
||||||
|
userContext = null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO - use DataTransferAuthorizable after looking up underlying component for consistentency
|
// TODO - use DataTransferAuthorizable after looking up underlying component for consistentency
|
||||||
final Resource resource = ResourceFactory.getComponentResource(resourceType, identifier, identifier);
|
final Resource resource = ResourceFactory.getComponentResource(resourceType, identifier, identifier);
|
||||||
final AuthorizationRequest request = new AuthorizationRequest.Builder()
|
final AuthorizationRequest request = new AuthorizationRequest.Builder()
|
||||||
|
@ -133,6 +144,7 @@ public class DataTransferResource extends ApplicationResource {
|
||||||
.anonymous(user.isAnonymous())
|
.anonymous(user.isAnonymous())
|
||||||
.accessAttempt(true)
|
.accessAttempt(true)
|
||||||
.action(RequestAction.WRITE)
|
.action(RequestAction.WRITE)
|
||||||
|
.userContext(userContext)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final AuthorizationResult result = authorizer.authorize(request);
|
final AuthorizationResult result = authorizer.authorize(request);
|
||||||
|
|
Loading…
Reference in New Issue