NIFI-12252 Removed Legacy FileAuthorizer

- Removed Legacy Authorized Users File property from FileUserGroupProvider
- Removed unused methods from FileAccessPolicyProvider and FileUserGroupProvider

Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com>

This closes #7910.
This commit is contained in:
exceptionfactory 2023-10-19 15:08:27 -05:00 committed by Pierre Villard
parent 98eef74dd8
commit 15c3bdeac1
No known key found for this signature in database
GPG Key ID: F92A93B30C07C6D5
12 changed files with 27 additions and 2074 deletions

View File

@ -33,7 +33,6 @@ import org.apache.nifi.util.FlowInfo;
import org.apache.nifi.util.FlowParser;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.apache.nifi.web.api.dto.PortDTO;
import org.apache.nifi.xml.processing.ProcessingException;
import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
@ -86,18 +85,14 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
private static final String AUTHORIZATIONS_XSD = "/authorizations.xsd";
private static final String JAXB_AUTHORIZATIONS_PATH = "org.apache.nifi.authorization.file.generated";
private static final String USERS_XSD = "/legacy-users.xsd";
private static final String JAXB_USERS_PATH = "org.apache.nifi.user.generated";
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_AUTHORIZATIONS_CONTEXT = initializeJaxbContext();
/**
* Load the JAXBContext.
*/
private static JAXBContext initializeJaxbContext(final String contextPath) {
private static JAXBContext initializeJaxbContext() {
try {
return JAXBContext.newInstance(contextPath, FileAuthorizer.class.getClassLoader());
return JAXBContext.newInstance(JAXB_AUTHORIZATIONS_PATH, FileAccessPolicyProvider.class.getClassLoader());
} catch (JAXBException e) {
throw new RuntimeException("Unable to create JAXBContext.");
}
@ -122,7 +117,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
static final String PROP_INITIAL_ADMIN_IDENTITY = "Initial Admin Identity";
static final Pattern NODE_IDENTITY_PATTERN = Pattern.compile(PROP_NODE_IDENTITY_PREFIX + "\\S+");
private Schema usersSchema;
private Schema authorizationsSchema;
private NiFiProperties properties;
private File authorizationsFile;
@ -131,9 +125,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
private String initialAdminIdentity;
private Set<String> nodeIdentities;
private String nodeGroupIdentifier;
private List<PortDTO> ports = new ArrayList<>();
private List<IdentityMapping> identityMappings;
private List<IdentityMapping> groupMappings;
private UserGroupProvider userGroupProvider;
private UserGroupProviderLookup userGroupProviderLookup;
@ -145,8 +136,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
try {
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
authorizationsSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(AUTHORIZATIONS_XSD));
usersSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(USERS_XSD));
authorizationsSchema = schemaFactory.newSchema(FileAccessPolicyProvider.class.getResource(AUTHORIZATIONS_XSD));
} catch (Exception e) {
throw new AuthorizerCreationException(e);
}
@ -173,7 +163,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
// get the authorizations file and ensure it exists
authorizationsFile = new File(authorizationsPath.getValue());
if (!authorizationsFile.exists()) {
logger.info("Creating new authorizations file at {}", new Object[] {authorizationsFile.getAbsolutePath()});
logger.info("Creating new authorizations file at {}", authorizationsFile.getAbsolutePath());
saveAuthorizations(new Authorizations());
}
@ -203,8 +193,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
}
// extract the identity mappings from nifi.properties if any are provided
identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
groupMappings = Collections.unmodifiableList(IdentityMappingUtil.getGroupMappings(properties));
List<IdentityMapping> identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
// get the value of the initial admin identity
final PropertyValue initialAdminIdentityProp = configurationContext.getProperty(PROP_INITIAL_ADMIN_IDENTITY);
@ -217,7 +206,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
if (matcher.matches() && !StringUtils.isBlank(entry.getValue())) {
final String mappedNodeIdentity = IdentityMappingUtil.mapIdentity(entry.getValue(), identityMappings);
nodeIdentities.add(mappedNodeIdentity);
logger.info("Added mapped node {} (raw node identity {})", new Object[]{mappedNodeIdentity, entry.getValue()});
logger.info("Added mapped node {} (raw node identity {})", mappedNodeIdentity, entry.getValue());
}
}
@ -255,7 +244,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
FileUtils.copyFile(authorizationsFile, restoreAuthorizationsFile, false, false, logger);
}
logger.info(String.format("Authorizations file loaded at %s", new Date().toString()));
logger.debug("Authorizations file loaded");
} catch (IOException | AuthorizerCreationException | JAXBException | IllegalStateException | SAXException e) {
throw new AuthorizerCreationException(e);
}
@ -419,7 +408,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
public synchronized void forciblyInheritFingerprint(final String fingerprint) throws AuthorizationAccessException {
final List<AccessPolicy> accessPolicies = parsePolicies(fingerprint);
if (isInheritable(accessPolicies)) {
if (isInheritable()) {
logger.debug("Inheriting cluster's Access Policies");
inheritAccessPolicies(accessPolicies);
} else {
@ -438,28 +427,20 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
@Override
public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
final List<AccessPolicy> accessPolicies;
try {
// ensure we can understand the proposed fingerprint
accessPolicies = parsePolicies(proposedFingerprint);
} catch (final AuthorizationAccessException e) {
throw new UninheritableAuthorizationsException("Unable to parse the proposed fingerprint: " + e);
}
// ensure we are in a proper state to inherit the fingerprint
if (!isInheritable(accessPolicies)) {
if (!isInheritable()) {
throw new UninheritableAuthorizationsException("Proposed fingerprint is not inheritable because the current access policies is not empty.");
}
}
private boolean isInheritable(final List<AccessPolicy> accessPolicies) {
private boolean isInheritable() {
return getAccessPolicies().isEmpty();
}
@Override
public String getFingerprint() throws AuthorizationAccessException {
final List<AccessPolicy> policies = new ArrayList<>(getAccessPolicies());
Collections.sort(policies, Comparator.comparing(AccessPolicy::getIdentifier));
policies.sort(Comparator.comparing(AccessPolicy::getIdentifier));
XMLStreamWriter writer = null;
final StringWriter out = new StringWriter();
@ -634,17 +615,14 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
/**
* Try to parse the flow configuration file to extract the root group id and port information.
*
* @throws SAXException if an error occurs creating the schema
*/
private void parseFlow() throws SAXException {
private void parseFlow() {
final FlowParser flowParser = new FlowParser();
final File flowConfigurationFile = properties.getFlowConfigurationFile();
final FlowInfo flowInfo = flowParser.parse(flowConfigurationFile);
if (flowInfo != null) {
rootGroupId = flowInfo.getRootGroupId();
ports = flowInfo.getPorts() == null ? new ArrayList<>() : flowInfo.getPorts();
}
}
@ -835,7 +813,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
/**
* Sets the given Policy to the state of the provided AccessPolicy. Users and Groups will be cleared and
* set to match the AccessPolicy, the resource and action will be set to match the AccessPolicy.
*
* Does not set the identifier.
*
* @param accessPolicy the AccessPolicy to transfer state from
@ -859,94 +836,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
}
}
/**
* 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 Policy matching the resource and action, or creates a new one and adds it to the list of policies.
*
* @param policies the policies to search through
* @param seedIdentity the seedIdentity to use when creating identifiers for new policies
* @param resource the resource for the policy
* @param action the action string for the police (R or RW)
* @return the matching policy or a new policy
*/
private Policy getOrCreatePolicy(final List<Policy> policies, final String seedIdentity, final String resource, final String action) {
Policy foundPolicy = null;
// try to find a policy with the same resource and actions
for (Policy policy : policies) {
if (policy.getResource().equals(resource) && policy.getAction().equals(action)) {
foundPolicy = policy;
break;
}
}
// if a matching policy wasn't found then create one
if (foundPolicy == null) {
final String uuidSeed = resource + action + seedIdentity;
final String policyIdentifier = IdentifierUtil.getIdentifier(uuidSeed);
foundPolicy = new Policy();
foundPolicy.setIdentifier(policyIdentifier);
foundPolicy.setResource(resource);
foundPolicy.setAction(action);
policies.add(foundPolicy);
}
return foundPolicy;
}
/**
* Saves the Authorizations instance by marshalling to a file, then re-populates the
* in-memory data structures and sets the new holder.
*
* Synchronized to ensure only one thread writes the file at a time.
*
* @param authorizations the authorizations to save and populate from

View File

@ -1,273 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.authorization;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
/**
* Provides authorizes requests to resources using policies persisted in a file.
*/
public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
private static final Logger logger = LoggerFactory.getLogger(FileAuthorizer.class);
private static final String FILE_USER_GROUP_PROVIDER_ID = "file-user-group-provider";
private static final String FILE_ACCESS_POLICY_PROVIDER_ID = "file-access-policy-provider";
private FileUserGroupProvider userGroupProvider = new FileUserGroupProvider();
private FileAccessPolicyProvider accessPolicyProvider = new FileAccessPolicyProvider();
@Override
public void initialize(final AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
// initialize the user group provider
userGroupProvider.initialize(new UserGroupProviderInitializationContext() {
@Override
public String getIdentifier() {
return FILE_USER_GROUP_PROVIDER_ID;
}
@Override
public UserGroupProviderLookup getUserGroupProviderLookup() {
return (identifier) -> null;
}
});
// initialize the access policy provider
accessPolicyProvider.initialize(new AccessPolicyProviderInitializationContext() {
@Override
public String getIdentifier() {
return FILE_ACCESS_POLICY_PROVIDER_ID;
}
@Override
public UserGroupProviderLookup getUserGroupProviderLookup() {
return (identifier) -> {
if (FILE_USER_GROUP_PROVIDER_ID.equals(identifier)) {
return userGroupProvider;
}
return null;
};
}
@Override
public AccessPolicyProviderLookup getAccessPolicyProviderLookup() {
return (identifier) -> null;
}
});
}
@Override
public void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
final Map<String, String> configurationProperties = configurationContext.getProperties();
// relay the relevant config
final Map<String, String> userGroupProperties = new HashMap<>();
if (configurationProperties.containsKey(FileUserGroupProvider.PROP_TENANTS_FILE)) {
userGroupProperties.put(FileUserGroupProvider.PROP_TENANTS_FILE, configurationProperties.get(FileUserGroupProvider.PROP_TENANTS_FILE));
}
// relay the relevant config
final Map<String, String> accessPolicyProperties = new HashMap<>();
accessPolicyProperties.put(FileAccessPolicyProvider.PROP_USER_GROUP_PROVIDER, FILE_USER_GROUP_PROVIDER_ID);
if (configurationProperties.containsKey(FileAccessPolicyProvider.PROP_AUTHORIZATIONS_FILE)) {
accessPolicyProperties.put(FileAccessPolicyProvider.PROP_AUTHORIZATIONS_FILE, configurationProperties.get(FileAccessPolicyProvider.PROP_AUTHORIZATIONS_FILE));
}
if (configurationProperties.containsKey(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)) {
accessPolicyProperties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY, configurationProperties.get(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY));
}
// ensure all node identities are seeded into the user provider
configurationProperties.forEach((property, value) -> {
final Matcher matcher = FileAccessPolicyProvider.NODE_IDENTITY_PATTERN.matcher(property);
if (matcher.matches()) {
accessPolicyProperties.put(property, value);
userGroupProperties.put(property.replace(FileAccessPolicyProvider.PROP_NODE_IDENTITY_PREFIX, FileUserGroupProvider.PROP_INITIAL_USER_IDENTITY_PREFIX), value);
}
});
// ensure the initial admin is seeded into the user provider if appropriate
if (configurationProperties.containsKey(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)) {
int i = 0;
while (true) {
final String key = FileUserGroupProvider.PROP_INITIAL_USER_IDENTITY_PREFIX + i++;
if (!userGroupProperties.containsKey(key)) {
userGroupProperties.put(key, configurationProperties.get(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY));
break;
}
}
}
// configure the user group provider
userGroupProvider.onConfigured(new StandardAuthorizerConfigurationContext(FILE_USER_GROUP_PROVIDER_ID, userGroupProperties));
// configure the access policy provider
accessPolicyProvider.onConfigured(new StandardAuthorizerConfigurationContext(FILE_USER_GROUP_PROVIDER_ID, accessPolicyProperties));
}
@Override
public void preDestruction() {
}
// ------------------ Groups ------------------
@Override
public synchronized Group doAddGroup(Group group) throws AuthorizationAccessException {
return userGroupProvider.addGroup(group);
}
@Override
public Group getGroup(String identifier) throws AuthorizationAccessException {
return userGroupProvider.getGroup(identifier);
}
@Override
public Group getGroupByName(String name) throws AuthorizationAccessException {
return userGroupProvider.getGroupByName(name);
}
@Override
public synchronized Group doUpdateGroup(Group group) throws AuthorizationAccessException {
return userGroupProvider.updateGroup(group);
}
@Override
public synchronized Group deleteGroup(Group group) throws AuthorizationAccessException {
return userGroupProvider.deleteGroup(group);
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
return userGroupProvider.getGroups();
}
// ------------------ Users ------------------
@Override
public synchronized User doAddUser(final User user) throws AuthorizationAccessException {
return userGroupProvider.addUser(user);
}
@Override
public User getUser(final String identifier) throws AuthorizationAccessException {
return userGroupProvider.getUser(identifier);
}
@Override
public User getUserByIdentity(final String identity) throws AuthorizationAccessException {
return userGroupProvider.getUserByIdentity(identity);
}
@Override
public synchronized User doUpdateUser(final User user) throws AuthorizationAccessException {
return userGroupProvider.updateUser(user);
}
@Override
public synchronized User deleteUser(final User user) throws AuthorizationAccessException {
return userGroupProvider.deleteUser(user);
}
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
return userGroupProvider.getUsers();
}
// ------------------ AccessPolicies ------------------
@Override
public synchronized AccessPolicy doAddAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
return accessPolicyProvider.addAccessPolicy(accessPolicy);
}
@Override
public AccessPolicy getAccessPolicy(final String identifier) throws AuthorizationAccessException {
return accessPolicyProvider.getAccessPolicy(identifier);
}
@Override
public synchronized AccessPolicy updateAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
return accessPolicyProvider.updateAccessPolicy(accessPolicy);
}
@Override
public synchronized AccessPolicy deleteAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
return accessPolicyProvider.deleteAccessPolicy(accessPolicy);
}
@Override
public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
return accessPolicyProvider.getAccessPolicies();
}
@Override
public void purgePoliciesUsersAndGroups() {
accessPolicyProvider.purgePolicies(true);
userGroupProvider.purgeUsersAndGroups();
}
@Override
public void backupPoliciesUsersAndGroups() {
try {
accessPolicyProvider.backupPolicies();
userGroupProvider.backupUsersAndGroups();
} catch (final JAXBException jaxb) {
throw new AuthorizationAccessException("Failed to backup policies", jaxb);
}
}
@AuthorizerContext
public void setNiFiProperties(NiFiProperties properties) {
userGroupProvider.setNiFiProperties(properties);
accessPolicyProvider.setNiFiProperties(properties);
}
@Override
public synchronized UsersAndAccessPolicies getUsersAndAccessPolicies() throws AuthorizationAccessException {
final AuthorizationsHolder authorizationsHolder = accessPolicyProvider.getAuthorizationsHolder();
final UserGroupHolder userGroupHolder = userGroupProvider.getUserGroupHolder();
return new UsersAndAccessPolicies() {
@Override
public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) {
return authorizationsHolder.getAccessPolicy(resourceIdentifier, action);
}
@Override
public User getUser(String identity) {
return userGroupHolder.getUser(identity);
}
@Override
public Set<Group> getGroups(String userIdentity) {
return userGroupHolder.getGroups(userIdentity);
}
};
}
}

View File

@ -80,19 +80,14 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
private static final String TENANTS_XSD = "/tenants.xsd";
private static final String JAXB_TENANTS_PATH = "org.apache.nifi.authorization.file.tenants.generated";
private static final String USERS_XSD = "/legacy-users.xsd";
private static final String JAXB_USERS_PATH = "org.apache.nifi.user.generated";
private static final JAXBContext JAXB_TENANTS_CONTEXT = initializeJaxbContext(JAXB_TENANTS_PATH);
private static final JAXBContext JAXB_USERS_CONTEXT = initializeJaxbContext(JAXB_USERS_PATH);
private static final JAXBContext JAXB_TENANTS_CONTEXT = initializeJaxbContext();
/**
* Load the JAXBContext.
*/
private static JAXBContext initializeJaxbContext(final String contextPath) {
private static JAXBContext initializeJaxbContext() {
try {
return JAXBContext.newInstance(contextPath, FileAuthorizer.class.getClassLoader());
return JAXBContext.newInstance(JAXB_TENANTS_PATH, FileUserGroupProvider.class.getClassLoader());
} catch (JAXBException e) {
throw new RuntimeException("Unable to create JAXBContext.", e);
}
@ -111,14 +106,11 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
static final String PROP_TENANTS_FILE = "Users File";
static final Pattern INITIAL_USER_IDENTITY_PATTERN = Pattern.compile(PROP_INITIAL_USER_IDENTITY_PREFIX + "\\S+");
private Schema usersSchema;
private Schema tenantsSchema;
private NiFiProperties properties;
private File tenantsFile;
private File restoreTenantsFile;
private Set<String> initialUserIdentities;
private List<IdentityMapping> identityMappings;
private List<IdentityMapping> groupMappings;
private final AtomicReference<UserGroupHolder> userGroupHolder = new AtomicReference<>();
@ -126,8 +118,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
public void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException {
try {
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
tenantsSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(TENANTS_XSD));
usersSchema = schemaFactory.newSchema(FileAuthorizer.class.getResource(USERS_XSD));
tenantsSchema = schemaFactory.newSchema(FileUserGroupProvider.class.getResource(TENANTS_XSD));
} catch (Exception e) {
throw new AuthorizerCreationException(e);
}
@ -144,7 +135,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
// get the tenants file and ensure it exists
tenantsFile = new File(tenantsPath.getValue());
if (!tenantsFile.exists()) {
logger.info("Creating new users file at {}", new Object[] {tenantsFile.getAbsolutePath()});
logger.info("Creating new users file at {}", tenantsFile.getAbsolutePath());
saveTenants(new Tenants());
}
@ -174,8 +165,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
}
// extract the identity and group mappings from nifi.properties if any are provided
identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
groupMappings = Collections.unmodifiableList(IdentityMappingUtil.getGroupMappings(properties));
List<IdentityMapping> identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
// extract any node identities
initialUserIdentities = new HashSet<>();
@ -193,7 +183,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
FileUtils.copyFile(tenantsFile, restoreTenantsFile, false, false, logger);
}
logger.info(String.format("Users/Groups file loaded at %s", new Date().toString()));
logger.debug("Users/Groups file loaded");
} catch (IOException | AuthorizerCreationException | JAXBException | IllegalStateException e) {
throw new AuthorizerCreationException(e);
}
@ -487,7 +477,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
final UsersAndGroups usersAndGroups = parseUsersAndGroups(fingerprint);
if (isInheritable(usersAndGroups)) {
if (isInheritable()) {
logger.debug("Inheriting cluster's Users & Groups");
inherit(usersAndGroups);
} else {
@ -526,21 +516,13 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
@Override
public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException {
final UsersAndGroups proposedUsersAndGroups;
try {
// ensure we understand the proposed fingerprint
proposedUsersAndGroups = parseUsersAndGroups(proposedFingerprint);
} catch (final AuthorizationAccessException e) {
throw new UninheritableAuthorizationsException("Unable to parse the proposed fingerprint: " + e);
}
// ensure we are in a proper state to inherit the fingerprint
if (!isInheritable(proposedUsersAndGroups)) {
if (!isInheritable()) {
throw new UninheritableAuthorizationsException("Proposed fingerprint is not inheritable because the current users and groups is not empty.");
}
}
private boolean isInheritable(final UsersAndGroups proposedUsersAndGroups) {
private boolean isInheritable() {
final UserGroupHolder usersAndGroups = userGroupHolder.get();
return usersAndGroups.getAllUsers().isEmpty() && usersAndGroups.getAllGroups().isEmpty();
}
@ -725,7 +707,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
private void populateInitialUsers(final Tenants tenants) {
for (String initialUserIdentity : initialUserIdentities) {
getOrCreateUser(tenants, initialUserIdentity);
createUser(tenants, initialUserIdentity);
}
}
@ -734,11 +716,10 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
*
* @param tenants the Tenants reference
* @param userIdentity the user identity to find or create
* @return the User from Tenants with the given identity, or a new instance that was added to Tenants
*/
private org.apache.nifi.authorization.file.tenants.generated.User getOrCreateUser(final Tenants tenants, final String userIdentity) {
private void createUser(final Tenants tenants, final String userIdentity) {
if (StringUtils.isBlank(userIdentity)) {
return null;
return;
}
org.apache.nifi.authorization.file.tenants.generated.User foundUser = null;
@ -756,45 +737,11 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
foundUser.setIdentity(userIdentity);
tenants.getUsers().getUser().add(foundUser);
}
return foundUser;
}
/**
* Finds the Group with the given name, or creates a new one and adds it to Tenants.
*
* @param tenants the Tenants reference
* @param groupName the name of the group to look for
* @return the Group from Tenants with the given name, or a new instance that was added to Tenants
*/
private org.apache.nifi.authorization.file.tenants.generated.Group getOrCreateGroup(final Tenants tenants, final String groupName) {
if (StringUtils.isBlank(groupName)) {
return null;
}
org.apache.nifi.authorization.file.tenants.generated.Group foundGroup = null;
for (org.apache.nifi.authorization.file.tenants.generated.Group group : tenants.getGroups().getGroup()) {
if (group.getName().equals(groupName)) {
foundGroup = group;
break;
}
}
if (foundGroup == null) {
final String newGroupIdentifier = IdentifierUtil.getIdentifier(groupName);
foundGroup = new org.apache.nifi.authorization.file.tenants.generated.Group();
foundGroup.setIdentifier(newGroupIdentifier);
foundGroup.setName(groupName);
tenants.getGroups().getGroup().add(foundGroup);
}
return foundGroup;
}
/**
* Saves the Authorizations instance by marshalling to a file, then re-populates the
* in-memory data structures and sets the new holder.
*
* Synchronized to ensure only one thread writes the file at a time.
*
* @param tenants the tenants to save and populate from

View File

@ -1,30 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.authorization;
/**
* Legacy Roles prior to the new authorization model.
*/
public enum Role {
ROLE_MONITOR,
ROLE_PROVENANCE,
ROLE_DFM,
ROLE_ADMIN,
ROLE_PROXY,
ROLE_NIFI;
}

View File

@ -1,113 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.authorization;
import org.apache.nifi.authorization.resource.ResourceType;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Defines the mapping from legacy roles to access policies.
*/
public final class RoleAccessPolicy {
static final String READ_ACTION = "R";
static final String WRITE_ACTION = "W";
private final String resource;
private final String action;
private RoleAccessPolicy(final String resource, final String action) {
this.resource = resource;
this.action = action;
}
public String getResource() {
return resource;
}
public String getAction() {
return action;
}
public static Map<Role,Set<RoleAccessPolicy>> getMappings(final String rootGroupId) {
final Map<Role,Set<RoleAccessPolicy>> roleAccessPolicies = new HashMap<>();
final Set<RoleAccessPolicy> monitorPolicies = new HashSet<>();
monitorPolicies.add(new RoleAccessPolicy(ResourceType.Flow.getValue(), READ_ACTION));
monitorPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
monitorPolicies.add(new RoleAccessPolicy(ResourceType.System.getValue(), READ_ACTION));
if (rootGroupId != null) {
monitorPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
}
roleAccessPolicies.put(Role.ROLE_MONITOR, Collections.unmodifiableSet(monitorPolicies));
final Set<RoleAccessPolicy> provenancePolicies = new HashSet<>();
provenancePolicies.add(new RoleAccessPolicy(ResourceType.Provenance.getValue(), READ_ACTION));
if (rootGroupId != null) {
provenancePolicies.add(new RoleAccessPolicy(ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
provenancePolicies.add(new RoleAccessPolicy(ResourceType.ProvenanceData.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
}
roleAccessPolicies.put(Role.ROLE_PROVENANCE, Collections.unmodifiableSet(provenancePolicies));
final Set<RoleAccessPolicy> dfmPolicies = new HashSet<>();
dfmPolicies.add(new RoleAccessPolicy(ResourceType.Flow.getValue(), READ_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), WRITE_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.System.getValue(), READ_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.RestrictedComponents.getValue(), WRITE_ACTION));
if (rootGroupId != null) {
dfmPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, WRITE_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
dfmPolicies.add(new RoleAccessPolicy(ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, WRITE_ACTION));
}
roleAccessPolicies.put(Role.ROLE_DFM, Collections.unmodifiableSet(dfmPolicies));
final Set<RoleAccessPolicy> adminPolicies = new HashSet<>();
adminPolicies.add(new RoleAccessPolicy(ResourceType.Flow.getValue(), READ_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
if (rootGroupId != null) {
adminPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
}
adminPolicies.add(new RoleAccessPolicy(ResourceType.Tenant.getValue(), READ_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Tenant.getValue(), WRITE_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Policy.getValue(), READ_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Policy.getValue(), WRITE_ACTION));
roleAccessPolicies.put(Role.ROLE_ADMIN, Collections.unmodifiableSet(adminPolicies));
final Set<RoleAccessPolicy> proxyPolicies = new HashSet<>();
proxyPolicies.add(new RoleAccessPolicy(ResourceType.Proxy.getValue(), WRITE_ACTION));
if (rootGroupId != null) {
proxyPolicies.add(new RoleAccessPolicy(ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
proxyPolicies.add(new RoleAccessPolicy(ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, WRITE_ACTION));
}
roleAccessPolicies.put(Role.ROLE_PROXY, Collections.unmodifiableSet(proxyPolicies));
final Set<RoleAccessPolicy> nifiPolicies = new HashSet<>();
nifiPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
nifiPolicies.add(new RoleAccessPolicy(ResourceType.SiteToSite.getValue(), READ_ACTION));
roleAccessPolicies.put(Role.ROLE_NIFI, Collections.unmodifiableSet(nifiPolicies));
return roleAccessPolicies;
}
}

View File

@ -1,15 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
org.apache.nifi.authorization.FileAuthorizer

View File

@ -1,64 +0,0 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- role -->
<xs:complexType name="Role">
<xs:attribute name="name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="ROLE_MONITOR"/>
<xs:enumeration value="ROLE_PROVENANCE"/>
<xs:enumeration value="ROLE_DFM"/>
<xs:enumeration value="ROLE_ADMIN"/>
<xs:enumeration value="ROLE_PROXY"/>
<xs:enumeration value="ROLE_NIFI"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
<!-- user -->
<xs:complexType name="User">
<xs:sequence>
<xs:element name="role" type="Role" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="dn">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:pattern value=".*[^\s].*"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="group">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:pattern value=".*[^\s].*"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
<!-- users -->
<xs:element name="users">
<xs:complexType>
<xs:sequence>
<xs:element name="user" type="User" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
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.
-->
<users>
<user dn="user1" group="group1">
<role name="ROLE_MONITOR"/>
<role name="ROLE_DFM" />
</user>
</users>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
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.
-->
<users>
<user dn="CN=user1, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US" group="group1">
<role name="ROLE_MONITOR"/>
</user>
<user dn="CN=user2, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US">
<role name="ROLE_PROVENANCE"/>
</user>
<user dn="CN=user3, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US">
<role name="ROLE_DFM"/>
</user>
<user dn="CN=user4, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US">
<role name="ROLE_ADMIN"/>
</user>
<user dn="CN=user5, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US">
<role name="ROLE_PROXY"/>
</user>
<user dn="CN=user6, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US">
<role name="ROLE_NIFI"/>
</user>
</users>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
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.
-->
<users>
<user dn="user1" group="group1">
<role name="ROLE_MONITOR"/>
</user>
<user dn="user2">
<role name="ROLE_PROVENANCE"/>
</user>
<user dn="user3">
<role name="ROLE_DFM"/>
</user>
<user dn="user4">
<role name="ROLE_ADMIN"/>
</user>
<user dn="user5">
<role name="ROLE_PROXY"/>
</user>
<user dn="user6">
<role name="ROLE_NIFI"/>
</user>
</users>

View File

@ -33,9 +33,6 @@
- Users File - The file where the FileUserGroupProvider will store users and groups.
- Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically
be used to load the users and groups into the Users File.
- Initial User Identity [unique key] - The identity of a users and systems to seed the Users File. The name of
each property must be unique, for example: "Initial User Identity A", "Initial User Identity B",
"Initial User Identity C" or "Initial User Identity 1", "Initial User Identity 2", "Initial User Identity 3"
@ -47,8 +44,6 @@
<identifier>file-user-group-provider</identifier>
<class>org.apache.nifi.authorization.FileUserGroupProvider</class>
<property name="Users File">./conf/users.xml</property>
<property name="Legacy Authorized Users File"></property>
<property name="Initial User Identity 1"></property>
</userGroupProvider>
@ -293,17 +288,11 @@
- Initial Admin Identity - The identity of an initial admin user that will be granted access to the UI and
given the ability to create additional users, groups, and policies. The value of this property could be
a DN when using certificates or LDAP, or a Kerberos principal. This property will only be used when there
are no other policies defined. If this property is specified then a Legacy Authorized Users File can not be specified.
are no other policies defined.
NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the initial admin identity,
so the value should be the unmapped identity. This identity must be found in the configured User Group Provider.
- Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically
converted to the new authorizations model. If this property is specified then an Initial Admin Identity can
not be specified, and this property will only be used when there are no other users, groups, and policies defined.
NOTE: Any users in the legacy users file must be found in the configured User Group Provider.
- 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.
The name of each property must be unique, for example for a three node cluster:
@ -324,7 +313,6 @@
<property name="User Group Provider">file-user-group-provider</property>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Initial Admin Identity"></property>
<property name="Legacy Authorized Users File"></property>
<property name="Node Identity 1"></property>
<property name="Node Group"></property>
</accessPolicyProvider>
@ -343,49 +331,6 @@
<property name="Access Policy Provider">file-access-policy-provider</property>
</authorizer>
<!--
NOTE: This Authorizer has been replaced with the more granular approach configured above with the Standard
Managed Authorizer. However, it is still available for backwards compatibility reasons.
The FileAuthorizer is NiFi's provided authorizer and has the following properties:
- Authorizations File - The file where the FileAuthorizer will store policies.
- Users File - The file where the FileAuthorizer will store users and groups.
- Initial Admin Identity - The identity of an initial admin user that will be granted access to the UI and
given the ability to create additional users, groups, and policies. The value of this property could be
a DN when using certificates or LDAP, or a Kerberos principal. This property will only be used when there
are no other users, groups, and policies defined. If this property is specified then a Legacy Authorized
Users File can not be specified.
NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the initial admin identity,
so the value should be the unmapped identity.
- Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically
converted to the new authorizations model. If this property is specified then an Initial Admin Identity can
not be specified, and this property will only be used when there are no other users, groups, and policies defined.
- 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.
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"
NOTE: Any identity mapping rules specified in nifi.properties will also be applied to the node identities,
so the values should be the unmapped identities (i.e. full DN from a certificate).
-->
<!-- <authorizer>
<identifier>file-provider</identifier>
<class>org.apache.nifi.authorization.FileAuthorizer</class>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Users File">./conf/users.xml</property>
<property name="Initial Admin Identity"></property>
<property name="Legacy Authorized Users File"></property>
<property name="Node Identity 1"></property>
</authorizer>
-->
<!--
Single User Authorizer requires the configuration of the SingleUserLoginIdentityProvider
in login-identity-provider.xml and in nifi.properties