This is an automated email from the ASF dual-hosted git repository.
mosermw pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 3ba40076ae NIFI-14391 Support to initiate administrative access for
group of users
3ba40076ae is described below
commit 3ba40076aefa8428ba29ab35e797cabb732e73af
Author: EndzeitBegins <[email protected]>
AuthorDate: Thu Apr 10 15:15:59 2025 +0200
NIFI-14391 Support to initiate administrative access for group of users
Signed-off-by: Mike Moser <[email protected]>
This closes #9868
---
nifi-docker/dockerhub/README.md | 8 +-
nifi-docker/dockerhub/sh/secure.sh | 2 +
.../src/main/asciidoc/administration-guide.adoc | 13 +-
.../authorization/FileAccessPolicyProvider.java | 84 +++++++++-
.../nifi/authorization/FileUserGroupProvider.java | 78 ++++++---
.../apache/nifi/authorization/IdentifierUtil.java | 35 ----
.../FileAccessPolicyProviderTest.java | 182 ++++++++++++++++++++-
.../authorization/FileUserGroupProviderTest.java | 53 +++++-
.../src/main/resources/conf/authorizers.xml | 21 ++-
9 files changed, 402 insertions(+), 74 deletions(-)
diff --git a/nifi-docker/dockerhub/README.md b/nifi-docker/dockerhub/README.md
index a3e8388ae5..825b1fc9f8 100644
--- a/nifi-docker/dockerhub/README.md
+++ b/nifi-docker/dockerhub/README.md
@@ -144,7 +144,7 @@ In this configuration, the user will need to provide
certificates and associated
if the LDAP provider of interest is operating in LDAPS or START_TLS modes,
certificates will additionally be needed.
Of particular note, is the `AUTH` environment variable which is set to `ldap`.
Additionally, the user must provide a
DN as provided by the configured LDAP server in the `INITIAL_ADMIN_IDENTITY`
environment variable. This value will be
-used to seed the instance with an initial user with administrative privileges.
Finally, this command makes use of a
+used to seed the instance with an initial user with administrative privileges.
Finally, this command makes use of a
volume to provide certificates on the host system to the container instance.
#### For a minimal, connection to an LDAP server using SIMPLE authentication:
@@ -183,7 +183,8 @@ volume to provide certificates on the host system to the
container instance.
In this configuration, the user will need to provide certificates and
associated configuration information.
Of particular note, is the `AUTH` environment variable which is set to `oidc`.
Additionally, the user must provide a
in the `INITIAL_ADMIN_IDENTITY` environment variable. This value will be used
to seed the instance with an initial
-user with administrative privileges.
+user with administrative privileges. Alternatively, the `INITIAL_ADMIN_GROUP`
environment variable can be specified
+to grant access to a group of users instead.
### For a minimal, connection to an OpenID server
@@ -198,6 +199,7 @@ user with administrative privileges.
-e TRUSTSTORE_PASSWORD=rHkWR1gDNW3R9hgbeRsT3OM3Ue0zwGtQqcFKJD2EXWE \
-e TRUSTSTORE_TYPE=JKS \
-e INITIAL_ADMIN_IDENTITY='test' \
+ -e INITIAL_ADMIN_GROUP='myGroup' \
-e
NIFI_SECURITY_USER_OIDC_DISCOVERY_URL=http://OPENID_SERVER_URL/auth/realms/OPENID_REALM/.well-known/openid-configuration
\
-e NIFI_SECURITY_USER_OIDC_CONNECT_TIMEOUT=10000 \
-e NIFI_SECURITY_USER_OIDC_READ_TIMEOUT=10000 \
@@ -214,7 +216,7 @@ user with administrative privileges.
apache/nifi:latest
- Make sure you've created realm, client and user in OpenID Server before with
the same user name defined in `INITIAL_ADMIN_IDENTITY` environment variable
-- You can read more information about theses Nifi security OIDC configurations
in this following link:
[https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#openid_connect](https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#openid_connect)
+- You can read more information about these Nifi security OIDC configurations
in this following link:
[https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#openid_connect](https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#openid_connect)
#### Clustering can be enabled by using the following properties to Docker
environment variable mappings.
diff --git a/nifi-docker/dockerhub/sh/secure.sh
b/nifi-docker/dockerhub/sh/secure.sh
index 4fff214e8c..62b2eec092 100755
--- a/nifi-docker/dockerhub/sh/secure.sh
+++ b/nifi-docker/dockerhub/sh/secure.sh
@@ -73,6 +73,8 @@ prop_replace 'nifi.security.user.login.identity.provider'
"${NIFI_SECURITY_USER_
# Establish initial user and an associated admin identity
sed -i -e 's|<property name="Initial User Identity 1"></property>|<property
name="Initial User Identity 1">'"${INITIAL_ADMIN_IDENTITY}"'</property>|'
${NIFI_HOME}/conf/authorizers.xml
sed -i -e 's|<property name="Initial Admin Identity"></property>|<property
name="Initial Admin Identity">'"${INITIAL_ADMIN_IDENTITY}"'</property>|'
${NIFI_HOME}/conf/authorizers.xml
+sed -i -e 's|<property name="Initial Group Identity 1"></property>|<property
name="Initial Group Identity 1">'"${INITIAL_ADMIN_GROUP}"'</property>|'
${NIFI_HOME}/conf/authorizers.xml
+sed -i -e 's|<property name="Initial Admin Group"></property>|<property
name="Initial Admin Group">'"${INITIAL_ADMIN_GROUP}"'</property>|'
${NIFI_HOME}/conf/authorizers.xml
if [ -n "${NODE_IDENTITY}" ]; then
sed -i -e 's|<property name="Node Identity 1"></property>|<property
name="Node Identity 1">'"${NODE_IDENTITY}"'</property>|'
${NIFI_HOME}/conf/authorizers.xml
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc
b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index f8e5a8eb50..01e89e9f6d 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -795,7 +795,8 @@ The default UserGroupProvider is the FileUserGroupProvider,
however, you can dev
* Users File - The file where the FileUserGroupProvider stores users and
groups. By default, the _users.xml_ in the `conf` directory is chosen.
* 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 - 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"
+* Initial User Identity - The identity of a user or system 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"
+* Initial Group Identity - The identity of a user group to seed the Users
File. The name of each property must be unique, for example: "Initial Group
Identity A", "Initial Group Identity B", "Initial Group Identity C" or "Initial
Group Identity 1", "Initial Group Identity 2", "Initial Group Identity 3"
==== LdapUserGroupProvider
@@ -911,14 +912,15 @@ The default AccessPolicyProvider is the
FileAccessPolicyProvider, however, you c
| Property Name | Description
|`User Group Provider` | The identifier for an User Group Provider defined
above that will be used to access users and groups for use in the managed
access policies.
|`Authorizations File` | The file where the FileAccessPolicyProvider will
store policies.
-|`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.
-|`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.
+|`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. If the property `Initial
Admin Group` is specified as w [...]
+|`Initial Admin Group` | The identity of an initial admin group 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.
+|`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 or Initial Admin Group can not be specified, and this property will
only be used when there are no other users, groups, and policies defined.
|`Node Identity` | 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"
|`Node Group` | The name of a group containing NiFi cluster nodes. The typical
use for this is when nodes are dynamically added/removed from the cluster.
|==================================================================================================================================================
-NOTE: The identities configured in the Initial Admin Identity, the Node
Identity properties, or discovered in a Legacy Authorized Users File must be
available in the configured User Group Provider.
+NOTE: The identities configured in the Initial Admin Identity, Initial Admin
Group, the Node Identity properties, or discovered in a Legacy Authorized Users
File must be available in the configured User Group Provider.
NOTE: Any users in the legacy users file must be found in the configured User
Group Provider.
@@ -959,6 +961,7 @@ NOTE: Any identity mapping rules specified in
_nifi.properties_ will also be app
==== Initial Admin Identity (New NiFi Instance)
If you are setting up a secured NiFi instance for the first time, you must
manually designate an “Initial Admin Identity” in the _authorizers.xml_ file.
This initial admin user is 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. If you are
the NiFi administrator, add yourself as the “Initial Admin Identity”.
+Alternatively, specifying an “Initial Admin Group” grants administrative
access to a group of users, mitigating dependence on a single person or the
need for a shared account.
After you have edited and saved the _authorizers.xml_ file, restart NiFi. The
“Initial Admin Identity” user and administrative policies are added to the
_users.xml_ and _authorizations.xml_ files during restart. Once NiFi starts,
the “Initial Admin Identity” user is able to access the UI and begin managing
users, groups, and policies.
@@ -1399,7 +1402,7 @@ The following tables summarize the global and component
policies assigned to eac
For details on the individual policies in the table, see <<access-policies>>.
-NOTE: NiFi fails to restart if values exist for both the `Initial Admin
Identity` and `Legacy Authorized Users File` properties. You can specify only
one of these values to initialize authorizations.
+NOTE: NiFi fails to restart if values exist for both the `Initial Admin
Identity` (or `Initial Admin Group`) and `Legacy Authorized Users File`
properties. You can specify only one of these values to initialize
authorizations.
NOTE: Do not manually edit the _authorizations.xml_ file. Create
authorizations only during initial setup and afterwards using the NiFi UI.
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
index 5363bb5619..9ab8de7aaa 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
@@ -16,6 +16,11 @@
*/
package org.apache.nifi.authorization;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBElement;
+import jakarta.xml.bind.JAXBException;
+import jakarta.xml.bind.Marshaller;
+import jakarta.xml.bind.Unmarshaller;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
@@ -46,11 +51,6 @@ import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
-import jakarta.xml.bind.JAXBContext;
-import jakarta.xml.bind.JAXBElement;
-import jakarta.xml.bind.JAXBException;
-import jakarta.xml.bind.Marshaller;
-import jakarta.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@@ -114,6 +114,7 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
static final String PROP_USER_GROUP_PROVIDER = "User Group Provider";
static final String PROP_AUTHORIZATIONS_FILE = "Authorizations File";
static final String PROP_INITIAL_ADMIN_IDENTITY = "Initial Admin Identity";
+ static final String PROP_INITIAL_ADMIN_GROUP = "Initial Admin Group";
static final Pattern NODE_IDENTITY_PATTERN =
Pattern.compile(PROP_NODE_IDENTITY_PREFIX + "\\S+");
private Schema authorizationsSchema;
@@ -122,6 +123,7 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
private File restoreAuthorizationsFile;
private String rootGroupId;
private String initialAdminIdentity;
+ private String initialAdminGroup;
private Set<String> nodeIdentities;
private String nodeGroupIdentifier;
@@ -198,6 +200,10 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
final PropertyValue initialAdminIdentityProp =
configurationContext.getProperty(PROP_INITIAL_ADMIN_IDENTITY);
initialAdminIdentity = initialAdminIdentityProp.isSet() ?
IdentityMappingUtil.mapIdentity(initialAdminIdentityProp.getValue(),
identityMappings) : null;
+ // get the value of the initial admin group
+ final PropertyValue initialAdminGroupProp =
configurationContext.getProperty(PROP_INITIAL_ADMIN_GROUP);
+ initialAdminGroup = initialAdminGroupProp.isSet() ?
IdentityMappingUtil.mapIdentity(initialAdminGroupProp.getValue(),
identityMappings) : null;
+
// extract any node identities
nodeIdentities = new HashSet<>();
for (Map.Entry<String, String> entry :
configurationContext.getProperties().entrySet()) {
@@ -566,14 +572,19 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
final AuthorizationsHolder authorizationsHolder = new
AuthorizationsHolder(authorizations);
final boolean emptyAuthorizations =
authorizationsHolder.getAllPolicies().isEmpty();
final boolean hasInitialAdminIdentity = (initialAdminIdentity != null
&& !StringUtils.isBlank(initialAdminIdentity));
+ final boolean hasInitialAdminGroup = (initialAdminGroup != null &&
!StringUtils.isBlank(initialAdminGroup));
- // 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, admin group or convert legacy users
if (emptyAuthorizations) {
parseFlow();
if (hasInitialAdminIdentity) {
logger.info("Populating authorizations for Initial Admin: {}",
initialAdminIdentity);
- populateInitialAdmin(authorizations);
+ populateInitialAdmin(authorizations, hasInitialAdminGroup);
+ }
+ if (hasInitialAdminGroup) {
+ logger.info("Populating authorizations for Initial Admin
Group: {}", initialAdminGroup);
+ populateInitialAdminGroup(authorizations);
}
populateNodes(authorizations);
@@ -625,14 +636,32 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
}
/**
- * Creates the initial admin user and policies for access the flow and
managing users and policies.
+ * Grants the initial admin user the policies for accessing the flow and
managing users and policies.
+ * <p>
+ * Either by creating the policies for the user itself or by making it a
member of the initial admin group.
*/
- private void populateInitialAdmin(final Authorizations authorizations) {
+ private void populateInitialAdmin(final Authorizations authorizations,
boolean hasInitialAdminGroup) {
final User initialAdmin =
userGroupProvider.getUserByIdentity(initialAdminIdentity);
if (initialAdmin == null) {
throw new AuthorizerCreationException("Unable to locate initial
admin " + initialAdminIdentity + " to seed policies");
}
+ if (hasInitialAdminGroup && userGroupProvider instanceof
ConfigurableUserGroupProvider configurableProvider) {
+ final Group initialAdminGroup =
userGroupProvider.getGroupByName(this.initialAdminGroup);
+ if (initialAdminGroup == null) {
+ throw new AuthorizerCreationException("Unable to locate
initial admin group " + this.initialAdminGroup + " to seed policies");
+ }
+
+ if (configurableProvider.isConfigurable(initialAdminGroup)) {
+ final Group updatedAdminGroup = new
Group.Builder(initialAdminGroup)
+ .addUser(initialAdmin.getIdentifier())
+ .build();
+
+ configurableProvider.updateGroup(updatedAdminGroup);
+ return; // user has access through membership; no need to add
policies to the user explicitly
+ }
+ }
+
// grant the user read access to the /flow resource
addUserToAccessPolicy(authorizations, ResourceType.Flow.getValue(),
initialAdmin.getIdentifier(), READ_CODE);
@@ -661,6 +690,43 @@ public class FileAccessPolicyProvider implements
ConfigurableAccessPolicyProvide
addUserToAccessPolicy(authorizations,
ResourceType.Controller.getValue(), initialAdmin.getIdentifier(), WRITE_CODE);
}
+ /**
+ * Grants the initial admin group the policies for accessing the flow and
managing users and policies.
+ */
+ private void populateInitialAdminGroup(final Authorizations
authorizations) {
+ final Group initialAdminGroup =
userGroupProvider.getGroupByName(this.initialAdminGroup);
+ if (initialAdminGroup == null) {
+ throw new AuthorizerCreationException("Unable to locate initial
admin group " + this.initialAdminGroup + " to seed policies");
+ }
+
+ // grant the group read access to the /flow resource
+ addGroupToAccessPolicy(authorizations, ResourceType.Flow.getValue(),
initialAdminGroup.getIdentifier(), READ_CODE);
+
+ // grant the group read access to the root process group resource
+ if (rootGroupId != null) {
+ addGroupToAccessPolicy(authorizations,
ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" +
rootGroupId, initialAdminGroup.getIdentifier(), READ_CODE);
+ addGroupToAccessPolicy(authorizations,
ResourceType.Data.getValue() + ResourceType.ProcessGroup.getValue() + "/" +
rootGroupId, initialAdminGroup.getIdentifier(), WRITE_CODE);
+
+ addGroupToAccessPolicy(authorizations,
ResourceType.ProcessGroup.getValue() + "/" + rootGroupId,
initialAdminGroup.getIdentifier(), READ_CODE);
+ addGroupToAccessPolicy(authorizations,
ResourceType.ProcessGroup.getValue() + "/" + rootGroupId,
initialAdminGroup.getIdentifier(), WRITE_CODE);
+ }
+
+ // grant the group write to restricted components
+ addGroupToAccessPolicy(authorizations,
ResourceType.RestrictedComponents.getValue(),
initialAdminGroup.getIdentifier(), WRITE_CODE);
+
+ // grant the group read/write access to the /tenants resource
+ addGroupToAccessPolicy(authorizations, ResourceType.Tenant.getValue(),
initialAdminGroup.getIdentifier(), READ_CODE);
+ addGroupToAccessPolicy(authorizations, ResourceType.Tenant.getValue(),
initialAdminGroup.getIdentifier(), WRITE_CODE);
+
+ // grant the group read/write access to the /policies resource
+ addGroupToAccessPolicy(authorizations, ResourceType.Policy.getValue(),
initialAdminGroup.getIdentifier(), READ_CODE);
+ addGroupToAccessPolicy(authorizations, ResourceType.Policy.getValue(),
initialAdminGroup.getIdentifier(), WRITE_CODE);
+
+ // grant the group read/write access to the /controller resource
+ addGroupToAccessPolicy(authorizations,
ResourceType.Controller.getValue(), initialAdminGroup.getIdentifier(),
READ_CODE);
+ addGroupToAccessPolicy(authorizations,
ResourceType.Controller.getValue(), initialAdminGroup.getIdentifier(),
WRITE_CODE);
+ }
+
/**
* Creates a user for each node and gives the nodes write permission to
/proxy.
*
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
index c56dce10ca..c72e8b38a2 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
@@ -16,6 +16,11 @@
*/
package org.apache.nifi.authorization;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBElement;
+import jakarta.xml.bind.JAXBException;
+import jakarta.xml.bind.Marshaller;
+import jakarta.xml.bind.Unmarshaller;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
@@ -42,11 +47,6 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.XMLConstants;
-import jakarta.xml.bind.JAXBContext;
-import jakarta.xml.bind.JAXBElement;
-import jakarta.xml.bind.JAXBException;
-import jakarta.xml.bind.Marshaller;
-import jakarta.xml.bind.Unmarshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@@ -70,7 +70,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
@@ -101,15 +100,18 @@ public class FileUserGroupProvider implements
ConfigurableUserGroupProvider {
private static final String IDENTITY_ATTR = "identity";
private static final String NAME_ATTR = "name";
- static final String PROP_INITIAL_USER_IDENTITY_PREFIX = "Initial User
Identity ";
static final String PROP_TENANTS_FILE = "Users File";
+ static final String PROP_INITIAL_USER_IDENTITY_PREFIX = "Initial User
Identity ";
static final Pattern INITIAL_USER_IDENTITY_PATTERN =
Pattern.compile(PROP_INITIAL_USER_IDENTITY_PREFIX + "\\S+");
+ static final String PROP_INITIAL_GROUP_IDENTITY_PREFIX = "Initial Group
Identity ";
+ static final Pattern INITIAL_GROUP_IDENTITY_PATTERN =
Pattern.compile(PROP_INITIAL_GROUP_IDENTITY_PREFIX + "\\S+");
private Schema tenantsSchema;
private NiFiProperties properties;
private File tenantsFile;
private File restoreTenantsFile;
private Set<String> initialUserIdentities;
+ private Set<String> initialGroupIdentities;
private final AtomicReference<UserGroupHolder> userGroupHolder = new
AtomicReference<>();
@@ -168,10 +170,19 @@ public class FileUserGroupProvider implements
ConfigurableUserGroupProvider {
// extract any node identities
initialUserIdentities = new HashSet<>();
+ initialGroupIdentities = new HashSet<>();
for (Map.Entry<String, String> entry :
configurationContext.getProperties().entrySet()) {
- Matcher matcher =
INITIAL_USER_IDENTITY_PATTERN.matcher(entry.getKey());
- if (matcher.matches() &&
!StringUtils.isBlank(entry.getValue())) {
-
initialUserIdentities.add(IdentityMappingUtil.mapIdentity(entry.getValue(),
identityMappings));
+ if
(INITIAL_USER_IDENTITY_PATTERN.matcher(entry.getKey()).matches()) {
+ if (StringUtils.isNotBlank(entry.getValue())) {
+
initialUserIdentities.add(IdentityMappingUtil.mapIdentity(entry.getValue(),
identityMappings));
+ }
+ continue;
+ }
+
+ if
(INITIAL_GROUP_IDENTITY_PATTERN.matcher(entry.getKey()).matches()) {
+ if (StringUtils.isNotBlank(entry.getValue())) {
+
initialGroupIdentities.add(IdentityMappingUtil.mapIdentity(entry.getValue(),
identityMappings));
+ }
}
}
@@ -670,6 +681,7 @@ public class FileUserGroupProvider implements
ConfigurableUserGroupProvider {
if (emptyTenants) {
populateInitialUsers(tenants);
+ populateInitialGroups(tenants);
// save any changes that were made and repopulate the holder
saveAndRefreshHolder(tenants);
@@ -709,6 +721,12 @@ public class FileUserGroupProvider implements
ConfigurableUserGroupProvider {
}
}
+ private void populateInitialGroups(final Tenants tenants) {
+ for (String initialGroupIdentity : initialGroupIdentities) {
+ createGroup(tenants, initialGroupIdentity);
+ }
+ }
+
/**
* Finds the User with the given identity, or creates a new one and adds
it to the Tenants.
*
@@ -720,21 +738,43 @@ public class FileUserGroupProvider implements
ConfigurableUserGroupProvider {
return;
}
- org.apache.nifi.authorization.file.tenants.generated.User foundUser =
null;
for (org.apache.nifi.authorization.file.tenants.generated.User user :
tenants.getUsers().getUser()) {
if (user.getIdentity().equals(userIdentity)) {
- foundUser = user;
- break;
+ return;
}
}
- if (foundUser == null) {
- final String userIdentifier =
IdentifierUtil.getIdentifier(userIdentity);
- foundUser = new
org.apache.nifi.authorization.file.tenants.generated.User();
- foundUser.setIdentifier(userIdentifier);
- foundUser.setIdentity(userIdentity);
- tenants.getUsers().getUser().add(foundUser);
+ final User builtUser = new
User.Builder().identifierGenerateFromSeed(userIdentity).identity(userIdentity).build();
+ final org.apache.nifi.authorization.file.tenants.generated.User
newUser =
+ new
org.apache.nifi.authorization.file.tenants.generated.User();
+ newUser.setIdentifier(builtUser.getIdentifier());
+ newUser.setIdentity(builtUser.getIdentity());
+ tenants.getUsers().getUser().add(newUser);
+ }
+
+ /**
+ * 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
+ */
+ private void createGroup(final Tenants tenants, final String groupName) {
+ if (StringUtils.isBlank(groupName)) {
+ return;
}
+
+ for (org.apache.nifi.authorization.file.tenants.generated.Group group
: tenants.getGroups().getGroup()) {
+ if (group.getName().equals(groupName)) {
+ return;
+ }
+ }
+
+ final Group builtGroup = new
Group.Builder().identifierGenerateFromSeed(groupName).name(groupName).build();
+ final org.apache.nifi.authorization.file.tenants.generated.Group
newGroup =
+ new
org.apache.nifi.authorization.file.tenants.generated.Group();
+ newGroup.setIdentifier(builtGroup.getIdentifier());
+ newGroup.setName(builtGroup.getName());
+ tenants.getGroups().getGroup().add(newGroup);
}
/**
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/IdentifierUtil.java
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/IdentifierUtil.java
deleted file mode 100644
index 0d4ec0764d..0000000000
---
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/IdentifierUtil.java
+++ /dev/null
@@ -1,35 +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.util.StringUtils;
-
-import java.nio.charset.StandardCharsets;
-import java.util.UUID;
-
-public final class IdentifierUtil {
-
- static String getIdentifier(final String seed) {
- if (StringUtils.isBlank(seed)) {
- return null;
- }
-
- return
UUID.nameUUIDFromBytes(seed.getBytes(StandardCharsets.UTF_8)).toString();
- }
-
- private IdentifierUtil() { }
-}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
index 4c4445a54d..2b436d5402 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
@@ -33,10 +33,12 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -187,6 +189,7 @@ public class FileAccessPolicyProviderTest {
ParameterLookup.EMPTY));
when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_TENANTS_FILE))).thenReturn(new
StandardPropertyValue(primaryTenants.getPath(), null, ParameterLookup.EMPTY));
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY))).thenReturn(new
StandardPropertyValue(null, null, ParameterLookup.EMPTY));
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP))).thenReturn(new
StandardPropertyValue(null, null, ParameterLookup.EMPTY));
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_USER_GROUP_PROVIDER))).thenReturn(new
StandardPropertyValue("user-group-provider", null,
ParameterLookup.EMPTY));
when(configurationContext.getProperties()).then((invocation) -> {
@@ -207,6 +210,11 @@ public class FileAccessPolicyProviderTest {
properties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY,
initialAdmin.getValue());
}
+ final PropertyValue initialAdminGroup =
configurationContext.getProperty(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP);
+ if (initialAdminGroup != null) {
+
properties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP,
initialAdminGroup.getValue());
+ }
+
int i = 1;
while (true) {
final String key =
FileAccessPolicyProvider.PROP_NODE_IDENTITY_PREFIX + i++;
@@ -229,6 +237,17 @@ public class FileAccessPolicyProviderTest {
}
}
+ i = 1;
+ while (true) {
+ final String key =
FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX + i++;
+ final PropertyValue value =
configurationContext.getProperty(key);
+ if (value == null) {
+ break;
+ } else {
+ properties.put(key, value.getValue());
+ }
+ }
+
// ensure the initial admin is seeded into the user provider if
appropriate
if
(properties.containsKey(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)) {
i = 0;
@@ -241,6 +260,18 @@ public class FileAccessPolicyProviderTest {
}
}
+ // ensure the initial admin group is seeded into the user provider
if appropriate
+ if
(properties.containsKey(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP)) {
+ i = 0;
+ while (true) {
+ final String key =
FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX + i++;
+ if (!properties.containsKey(key)) {
+ properties.put(key,
properties.get(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP));
+ break;
+ }
+ }
+ }
+
return properties;
});
@@ -350,7 +381,7 @@ public class FileAccessPolicyProviderTest {
// setup NiFi properties to return a file that does not exist
properties = mock(NiFiProperties.class);
when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
- when(properties.getFlowConfigurationFile()).thenReturn(new
File("src/test/resources/does-not-exist.json.gz"));
+ when(properties.getFlowConfigurationFile()).thenReturn(null);
userGroupProvider.setNiFiProperties(properties);
accessPolicyProvider.setNiFiProperties(properties);
@@ -385,6 +416,155 @@ public class FileAccessPolicyProviderTest {
assertFalse(foundRootGroupPolicy);
}
+ @Test
+ public void testOnConfiguredWhenInitialAdminGroupProvided() throws
Exception {
+ final String adminGroupName = "admin-group";
+
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP)))
+ .thenReturn(new StandardPropertyValue(adminGroupName, null,
ParameterLookup.EMPTY));
+
+ writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
+ writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
+
+ userGroupProvider.onConfigured(configurationContext);
+ accessPolicyProvider.onConfigured(configurationContext);
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ final Group adminGroup = groups.iterator().next();
+ assertEquals(adminGroupName, adminGroup.getName());
+
+ final Set<AccessPolicy> policies =
accessPolicyProvider.getAccessPolicies();
+ assertEquals(12, policies.size());
+
+ final String rootGroupResource = ResourceType.ProcessGroup.getValue()
+ "/" + ROOT_GROUP_ID;
+
+ boolean foundRootGroupPolicy = false;
+ for (AccessPolicy policy : policies) {
+ if (policy.getResource().equals(rootGroupResource)) {
+ foundRootGroupPolicy = true;
+ break;
+ }
+ }
+
+ assertTrue(foundRootGroupPolicy);
+ }
+
+ @Test
+ public void testOnConfiguredWhenInitialAdminGroupProvidedAndNoFlowExists()
throws Exception {
+ // setup NiFi properties to return a file that does not exist
+ properties = mock(NiFiProperties.class);
+
when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
+ when(properties.getFlowConfigurationFile()).thenReturn(new
File("src/test/resources/does-not-exist.json.gz"));
+
+ userGroupProvider.setNiFiProperties(properties);
+ accessPolicyProvider.setNiFiProperties(properties);
+
+ final String adminGroupName = "admin-group";
+
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP)))
+ .thenReturn(new StandardPropertyValue(adminGroupName, null,
ParameterLookup.EMPTY));
+
+ writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
+ writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
+
+ userGroupProvider.onConfigured(configurationContext);
+ accessPolicyProvider.onConfigured(configurationContext);
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ final Group adminGroup = groups.iterator().next();
+ assertEquals(adminGroupName, adminGroup.getName());
+
+ final Set<AccessPolicy> policies =
accessPolicyProvider.getAccessPolicies();
+ assertEquals(8, policies.size());
+
+ final String rootGroupResource = ResourceType.ProcessGroup.getValue()
+ "/" + ROOT_GROUP_ID;
+
+ boolean foundRootGroupPolicy = false;
+ for (AccessPolicy policy : policies) {
+ if (policy.getResource().equals(rootGroupResource)) {
+ foundRootGroupPolicy = true;
+ break;
+ }
+ }
+
+ assertFalse(foundRootGroupPolicy);
+ }
+
+ @Test
+ public void testOnConfiguredWhenInitialAdminGroupProvidedAndFlowIsNull()
throws Exception {
+ // setup NiFi properties to return a file that does not exist
+ properties = mock(NiFiProperties.class);
+
when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
+ when(properties.getFlowConfigurationFile()).thenReturn(null);
+
+ userGroupProvider.setNiFiProperties(properties);
+ accessPolicyProvider.setNiFiProperties(properties);
+
+ final String adminGroupName = "admin-group";
+
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP)))
+ .thenReturn(new StandardPropertyValue(adminGroupName, null,
ParameterLookup.EMPTY));
+
+ writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
+ writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
+
+ userGroupProvider.onConfigured(configurationContext);
+ accessPolicyProvider.onConfigured(configurationContext);
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ final Group adminGroup = groups.iterator().next();
+ assertEquals(adminGroupName, adminGroup.getName());
+
+ final Set<AccessPolicy> policies =
accessPolicyProvider.getAccessPolicies();
+ assertEquals(8, policies.size());
+
+ final String rootGroupResource = ResourceType.ProcessGroup.getValue()
+ "/" + ROOT_GROUP_ID;
+
+ boolean foundRootGroupPolicy = false;
+ for (AccessPolicy policy : policies) {
+ if (policy.getResource().equals(rootGroupResource)) {
+ foundRootGroupPolicy = true;
+ break;
+ }
+ }
+
+ assertFalse(foundRootGroupPolicy);
+ }
+
+ @Test
+ public void
testOnConfiguredWhenBothInitialAdminAndInitialAdminGroupProvided() throws
Exception {
+ final String adminIdentity = "admin-user";
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)))
+ .thenReturn(new StandardPropertyValue(adminIdentity, null,
ParameterLookup.EMPTY));
+
+ final String adminGroupName = "admin-group";
+
when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_GROUP)))
+ .thenReturn(new StandardPropertyValue(adminGroupName, null,
ParameterLookup.EMPTY));
+
+ writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
+ writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
+
+ userGroupProvider.onConfigured(configurationContext);
+ accessPolicyProvider.onConfigured(configurationContext);
+
+ final Set<User> users = userGroupProvider.getUsers();
+ final User adminUser = users.iterator().next();
+ assertEquals(adminIdentity, adminUser.getIdentity());
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ final Group adminGroup = groups.iterator().next();
+ assertEquals(adminGroupName, adminGroup.getName());
+ assertEquals(Set.of(adminUser.getIdentifier()), adminGroup.getUsers());
+
+ final Set<AccessPolicy> policies =
accessPolicyProvider.getAccessPolicies();
+ assertEquals(12, policies.size());
+ // admin user is a member of admin group; no need to grant access
right to the user itself
+ final Set<String> usersWithPolicies = policies.stream()
+ .flatMap(policy -> policy.getUsers().stream())
+ .collect(Collectors.toUnmodifiableSet());
+ assertEquals(Collections.emptySet(), usersWithPolicies);
+ }
+
@Test
public void testOnConfiguredWhenInitialAdminProvidedWithIdentityMapping()
throws Exception {
final Properties props = new Properties();
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
index 54e998d4bd..e499f8a8c4 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
@@ -125,6 +125,17 @@ public class FileUserGroupProviderTest {
}
}
+ int j = 1;
+ while (true) {
+ final String key =
FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX + j++;
+ final PropertyValue value =
configurationContext.getProperty(key);
+ if (value == null) {
+ break;
+ } else {
+ properties.put(key, value.getValue());
+ }
+ }
+
return properties;
});
@@ -140,12 +151,14 @@ public class FileUserGroupProviderTest {
}
@Test
- public void testOnConfiguredWhenInitialUsersNotProvided() throws Exception
{
+ public void testOnConfiguredWhenInitialUsersAndInitialGroupsNotProvided()
throws Exception {
writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
userGroupProvider.onConfigured(configurationContext);
final Set<User> users = userGroupProvider.getUsers();
assertEquals(0, users.size());
+ final Set<Group> groups = userGroupProvider.getGroups();
+ assertEquals(0, groups.size());
}
@Test
@@ -172,6 +185,26 @@ public class FileUserGroupProviderTest {
assertTrue(users.contains(new
User.Builder().identifierGenerateFromSeed(nodeIdentity2).identity(nodeIdentity2).build()));
}
+ @Test
+ public void testOnConfiguredWhenInitialGroupsProvided() throws Exception {
+ final String adminGroupIdentity = "admin-group";
+ final String otherGroupIdentity = "other-group";
+
+
when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX
+ "1")))
+ .thenReturn(new StandardPropertyValue(adminGroupIdentity,
null, ParameterLookup.EMPTY));
+
when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX
+ "2")))
+ .thenReturn(new StandardPropertyValue(otherGroupIdentity,
null, ParameterLookup.EMPTY));
+
+ writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
+ userGroupProvider.onConfigured(configurationContext);
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ assertEquals(2, groups.size());
+
+ assertTrue(groups.contains(new
Group.Builder().identifierGenerateFromSeed(adminGroupIdentity).name(adminGroupIdentity).build()));
+ assertTrue(groups.contains(new
Group.Builder().identifierGenerateFromSeed(otherGroupIdentity).name(otherGroupIdentity).build()));
+ }
+
@Test
public void testOnConfiguredWhenTenantsExistAndInitialUsersProvided()
throws Exception {
final String adminIdentity = "admin-user";
@@ -196,6 +229,24 @@ public class FileUserGroupProviderTest {
assertTrue(users.contains(new
User.Builder().identifier("user-2").identity("user-2").build()));
}
+ @Test
+ public void testOnConfiguredWhenTenantsExistAndInitialGroupsProvided()
throws Exception {
+ final String adminGroupIdentity = "admin-group";
+ final String otherGroupIdentity = "other-group";
+
+ // despite setting initial groups, they will not be loaded as the
tenants file is non-empty
+
when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX
+ "1")))
+ .thenReturn(new StandardPropertyValue(adminGroupIdentity,
null, ParameterLookup.EMPTY));
+
when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_INITIAL_GROUP_IDENTITY_PREFIX
+ "2")))
+ .thenReturn(new StandardPropertyValue(otherGroupIdentity,
null, ParameterLookup.EMPTY));
+
+ writeFile(primaryTenants, SIMPLE_TENANTS_BY_USER);
+ userGroupProvider.onConfigured(configurationContext);
+
+ final Set<Group> groups = userGroupProvider.getGroups();
+ assertEquals(0, groups.size());
+ }
+
@Test
public void testOnConfiguredWhenTenantsFileDoesNotExist() throws Exception
{
writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
index b12ad65b11..4f2fb936ff 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
+++
b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
@@ -33,18 +33,26 @@
- Users File - The file where the FileUserGroupProvider will store
users and groups.
- - Initial User Identity [unique key] - The identity of a users and
systems to seed the Users File. The name of
+ - Initial User Identity [unique key] - The identity of a user or
system 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"
NOTE: Any identity mapping rules specified in nifi.properties will
also be applied to the user identities,
so the values should be the unmapped identities (i.e. full DN from
a certificate).
+
+ - Initial Group Identity [unique key] - The identity of a user group
to seed the Users File. The name of
+ each property must be unique, for example: "Initial Group Identity
A", "Initial Group Identity B",
+ "Initial Group Identity C" or "Initial Group Identity 1", "Initial
Group Identity 2", "Initial Group Identity 3"
+
+ NOTE: Any identity mapping rules specified in nifi.properties will
also be applied to the group identities,
+ so the values should be the unmapped identities (i.e. full DN from
a certificate).
-->
<userGroupProvider>
<identifier>file-user-group-provider</identifier>
<class>org.apache.nifi.authorization.FileUserGroupProvider</class>
<property name="Users File">./conf/users.xml</property>
<property name="Initial User Identity 1"></property>
+ <property name="Initial Group Identity 1"></property>
</userGroupProvider>
<!--
@@ -264,10 +272,20 @@
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 the property "Initial Admin Group" is specified as well, the
initial admin user will be a member of that group,
+ in case the configured user group provider supports updating the
group.
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.
+ - Initial Admin Group - The identity of an initial admin group 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.
+
+ NOTE: Any identity mapping rules specified in nifi.properties will
also be applied to the initial admin group,
+ so the value should be the unmapped identity. This identity 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:
@@ -288,6 +306,7 @@
<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="Initial Admin Group"></property>
<property name="Node Identity 1"></property>
<property name="Node Group"></property>
</accessPolicyProvider>