NIFI-2390 Separating of users and groups from authorizations.xml into separate 
file. This closes #735


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/5e4ba045
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/5e4ba045
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/5e4ba045

Branch: refs/heads/master
Commit: 5e4ba04589686963de1fc4218dd1365197c31c02
Parents: 01adb05
Author: Bryan Bende <[email protected]>
Authored: Tue Jul 26 17:02:25 2016 -0400
Committer: Matt Gilman <[email protected]>
Committed: Thu Jul 28 16:41:52 2016 -0400

----------------------------------------------------------------------
 .../nifi-framework/nifi-file-authorizer/pom.xml |  16 +-
 .../authorization/AuthorizationsHolder.java     |  29 +-
 .../nifi/authorization/FileAuthorizer.java      | 295 ++++++++++++-------
 .../src/main/xsd/authorizations.xsd             |  72 -----
 .../src/main/xsd/legacy-users.xsd               |  64 ++++
 .../src/main/xsd/tenants.xsd                    |  96 ++++++
 .../nifi-file-authorizer/src/main/xsd/users.xsd |  64 ----
 .../nifi/authorization/FileAuthorizerTest.java  | 275 +++++++++++------
 .../src/main/resources/conf/authorizers.xml     |   5 +-
 9 files changed, 575 insertions(+), 341 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
index 8ea509c..433f8a2 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
@@ -47,13 +47,25 @@
                         </configuration>
                     </execution>
                     <execution>
+                        <id>tenants</id>
+                        <goals>
+                            <goal>xjc</goal>
+                        </goals>
+                        <configuration>
+                            <schemaDirectory>src/main/xsd</schemaDirectory>
+                            <schemaFiles>tenants.xsd</schemaFiles>
+                            
<packageName>org.apache.nifi.authorization.file.tenants.generated</packageName>
+                            <clearOutputDir>false</clearOutputDir>
+                        </configuration>
+                    </execution>
+                    <execution>
                         <id>users</id>
                         <goals>
                             <goal>xjc</goal>
                         </goals>
                         <configuration>
                             <schemaDirectory>src/main/xsd</schemaDirectory>
-                            <schemaFiles>users.xsd</schemaFiles>
+                            <schemaFiles>legacy-users.xsd</schemaFiles>
                             
<packageName>org.apache.nifi.user.generated</packageName>
                             <clearOutputDir>false</clearOutputDir>
                         </configuration>
@@ -67,7 +79,7 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-checkstyle-plugin</artifactId>
                 <configuration>
-                    
<excludes>**/authorization/file/generated/*.java,**/user/generated/*.java</excludes>
+                    
<excludes>**/authorization/file/generated/*.java,**/authorization/file/tenants/generated/*.java,**/user/generated/*.java</excludes>
                 </configuration>
             </plugin>            
         </plugins>

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
index 383281d..e407289 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
@@ -18,9 +18,10 @@ package org.apache.nifi.authorization;
 
 
 import org.apache.nifi.authorization.file.generated.Authorizations;
-import org.apache.nifi.authorization.file.generated.Groups;
 import org.apache.nifi.authorization.file.generated.Policies;
-import org.apache.nifi.authorization.file.generated.Users;
+import org.apache.nifi.authorization.file.tenants.generated.Groups;
+import org.apache.nifi.authorization.file.tenants.generated.Tenants;
+import org.apache.nifi.authorization.file.tenants.generated.Users;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -33,6 +34,7 @@ import java.util.Set;
  */
 public class AuthorizationsHolder implements UsersAndAccessPolicies {
 
+    private final Tenants tenants;
     private final Authorizations authorizations;
 
     private final Set<AccessPolicy> allPolicies;
@@ -52,15 +54,16 @@ public class AuthorizationsHolder implements 
UsersAndAccessPolicies {
      *
      * @param authorizations the current authorizations instance
      */
-    public AuthorizationsHolder(final Authorizations authorizations) {
+    public AuthorizationsHolder(final Authorizations authorizations, final 
Tenants tenants) {
         this.authorizations = authorizations;
+        this.tenants = tenants;
 
         // load all users
-        final Users users = authorizations.getUsers();
+        final Users users = tenants.getUsers();
         final Set<User> allUsers = 
Collections.unmodifiableSet(createUsers(users));
 
         // load all groups
-        final Groups groups = authorizations.getGroups();
+        final Groups groups = tenants.getGroups();
         final Set<Group> allGroups = 
Collections.unmodifiableSet(createGroups(groups, users));
 
         // load all access policies
@@ -152,13 +155,13 @@ public class AuthorizationsHolder implements 
UsersAndAccessPolicies {
      * @param users the JAXB Users
      * @return a set of API Users matching the provided JAXB Users
      */
-    private Set<User> 
createUsers(org.apache.nifi.authorization.file.generated.Users users) {
+    private Set<User> 
createUsers(org.apache.nifi.authorization.file.tenants.generated.Users users) {
         Set<User> allUsers = new HashSet<>();
         if (users == null || users.getUser() == null) {
             return allUsers;
         }
 
-        for (org.apache.nifi.authorization.file.generated.User user : 
users.getUser()) {
+        for (org.apache.nifi.authorization.file.tenants.generated.User user : 
users.getUser()) {
             final User.Builder builder = new User.Builder()
                     .identity(user.getIdentity())
                     .identifier(user.getIdentifier());
@@ -175,19 +178,19 @@ public class AuthorizationsHolder implements 
UsersAndAccessPolicies {
      * @param groups the JAXB Groups
      * @return a set of API Groups matching the provided JAXB Groups
      */
-    private Set<Group> 
createGroups(org.apache.nifi.authorization.file.generated.Groups groups,
-                                    
org.apache.nifi.authorization.file.generated.Users users) {
+    private Set<Group> 
createGroups(org.apache.nifi.authorization.file.tenants.generated.Groups groups,
+                                    
org.apache.nifi.authorization.file.tenants.generated.Users users) {
         Set<Group> allGroups = new HashSet<>();
         if (groups == null || groups.getGroup() == null) {
             return allGroups;
         }
 
-        for (org.apache.nifi.authorization.file.generated.Group group : 
groups.getGroup()) {
+        for (org.apache.nifi.authorization.file.tenants.generated.Group group 
: groups.getGroup()) {
             final Group.Builder builder = new Group.Builder()
                     .identifier(group.getIdentifier())
                     .name(group.getName());
 
-            for (org.apache.nifi.authorization.file.generated.Group.User 
groupUser : group.getUser()) {
+            for 
(org.apache.nifi.authorization.file.tenants.generated.Group.User groupUser : 
group.getUser()) {
                 builder.addUser(groupUser.getIdentifier());
             }
 
@@ -304,6 +307,10 @@ public class AuthorizationsHolder implements 
UsersAndAccessPolicies {
         return authorizations;
     }
 
+    public Tenants getTenants() {
+        return tenants;
+    }
+
     public Set<AccessPolicy> getAllPolicies() {
         return allPolicies;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
index 1cd40ea..a7e41ea 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
@@ -21,10 +21,11 @@ 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.authorization.file.generated.Authorizations;
-import org.apache.nifi.authorization.file.generated.Groups;
+import org.apache.nifi.authorization.file.tenants.generated.Groups;
 import org.apache.nifi.authorization.file.generated.Policies;
 import org.apache.nifi.authorization.file.generated.Policy;
-import org.apache.nifi.authorization.file.generated.Users;
+import org.apache.nifi.authorization.file.tenants.generated.Users;
+import org.apache.nifi.authorization.file.tenants.generated.Tenants;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.authorization.util.IdentityMapping;
@@ -72,10 +73,14 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     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 = "/users.xsd";
+    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_AUTHORIZATIONS_CONTEXT = 
initializeJaxbContext(JAXB_AUTHORIZATIONS_PATH);
+    private static final JAXBContext JAXB_TENANTS_CONTEXT = 
initializeJaxbContext(JAXB_TENANTS_PATH);
     private static final JAXBContext JAXB_USERS_CONTEXT = 
initializeJaxbContext(JAXB_USERS_PATH);
 
     /**
@@ -93,16 +98,20 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     static final String WRITE_CODE = "W";
 
     static final String PROP_AUTHORIZATIONS_FILE = "Authorizations File";
+    static final String PROP_TENANTS_FILE = "Users File";
     static final String PROP_INITIAL_ADMIN_IDENTITY = "Initial Admin Identity";
     static final String PROP_LEGACY_AUTHORIZED_USERS_FILE = "Legacy Authorized 
Users File";
     static final Pattern NODE_IDENTITY_PATTERN = Pattern.compile("Node 
Identity \\S+");
 
     private Schema usersSchema;
+    private Schema tenantsSchema;
     private Schema authorizationsSchema;
     private SchemaFactory schemaFactory;
     private NiFiProperties properties;
+    private File tenantsFile;
     private File authorizationsFile;
     private File restoreAuthorizationsFile;
+    private File restoreTenantsFile;
     private String rootGroupId;
     private String initialAdminIdentity;
     private String legacyAuthorizedUsersFile;
@@ -116,6 +125,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     public void initialize(final AuthorizerInitializationContext 
initializationContext) throws AuthorizerCreationException {
         try {
             schemaFactory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            tenantsSchema = 
schemaFactory.newSchema(FileAuthorizer.class.getResource(TENANTS_XSD));
             authorizationsSchema = 
schemaFactory.newSchema(FileAuthorizer.class.getResource(AUTHORIZATIONS_XSD));
             usersSchema = 
schemaFactory.newSchema(FileAuthorizer.class.getResource(USERS_XSD));
         } catch (Exception e) {
@@ -126,6 +136,18 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     @Override
     public void doOnConfigured(final AuthorizerConfigurationContext 
configurationContext) throws AuthorizerCreationException {
         try {
+            final PropertyValue tenantsPath = 
configurationContext.getProperty(PROP_TENANTS_FILE);
+            if (StringUtils.isBlank(tenantsPath.getValue())) {
+                throw new AuthorizerCreationException("The users file must be 
specified.");
+            }
+
+            // 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()});
+                saveTenants(new Tenants());
+            }
+
             final PropertyValue authorizationsPath = 
configurationContext.getProperty(PROP_AUTHORIZATIONS_FILE);
             if (StringUtils.isBlank(authorizationsPath.getValue())) {
                 throw new AuthorizerCreationException("The authorizations file 
must be specified.");
@@ -135,10 +157,11 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             authorizationsFile = new File(authorizationsPath.getValue());
             if (!authorizationsFile.exists()) {
                 logger.info("Creating new authorizations file at {}", new 
Object[] {authorizationsFile.getAbsolutePath()});
-                saveAndRefreshHolder(new Authorizations());
+                saveAuthorizations(new Authorizations());
             }
 
             final File authorizationsFileDirectory = 
authorizationsFile.getAbsoluteFile().getParentFile();
+            final File tenantsFileDirectory = 
tenantsFile.getAbsoluteFile().getParentFile();
 
             // the restore directory is optional and may be null
             final File restoreDirectory = properties.getRestoreDirectory();
@@ -146,18 +169,26 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                 // sanity check that restore directory is a directory, 
creating it if necessary
                 FileUtils.ensureDirectoryExistAndCanAccess(restoreDirectory);
 
-                // check that restore directory is not the same as the primary 
directory
+                // check that restore directory is not the same as the 
authorizations directory
                 if 
(authorizationsFileDirectory.getAbsolutePath().equals(restoreDirectory.getAbsolutePath()))
 {
                     throw new 
AuthorizerCreationException(String.format("Authorizations file directory '%s' 
is the same as restore directory '%s' ",
                             authorizationsFileDirectory.getAbsolutePath(), 
restoreDirectory.getAbsolutePath()));
                 }
 
+                // check that restore directory is not the same as the user's 
directory
+                if 
(tenantsFileDirectory.getAbsolutePath().equals(restoreDirectory.getAbsolutePath()))
 {
+                    throw new AuthorizerCreationException(String.format("Users 
file directory '%s' is the same as restore directory '%s' ",
+                            tenantsFileDirectory.getAbsolutePath(), 
restoreDirectory.getAbsolutePath()));
+                }
+
                 // the restore copy will have same file name, but reside in a 
different directory
                 restoreAuthorizationsFile = new File(restoreDirectory, 
authorizationsFile.getName());
+                restoreTenantsFile = new File(restoreDirectory, 
tenantsFile.getName());
 
                 try {
                     // sync the primary copy with the restore copy
                     FileUtils.syncWithRestore(authorizationsFile, 
restoreAuthorizationsFile, logger);
+                    FileUtils.syncWithRestore(tenantsFile, restoreTenantsFile, 
logger);
                 } catch (final IOException | IllegalStateException ioe) {
                     throw new AuthorizerCreationException(ioe);
                 }
@@ -191,6 +222,11 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                 FileUtils.copyFile(authorizationsFile, 
restoreAuthorizationsFile, false, false, logger);
             }
 
+            // if we've copied the authorizations file to a restore directory 
synchronize it
+            if (restoreTenantsFile != null) {
+                FileUtils.copyFile(tenantsFile, restoreTenantsFile, false, 
false, logger);
+            }
+
             logger.info(String.format("Authorizations file loaded at %s", new 
Date().toString()));
 
         } catch (IOException | AuthorizerCreationException | JAXBException | 
IllegalStateException | SAXException e) {
@@ -207,23 +243,20 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
      */
     private synchronized void load() throws JAXBException, IOException, 
IllegalStateException, SAXException {
         // attempt to unmarshal
-        final Unmarshaller unmarshaller = 
JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
-        unmarshaller.setSchema(authorizationsSchema);
-        final JAXBElement<Authorizations> element = unmarshaller.unmarshal(new 
StreamSource(authorizationsFile), Authorizations.class);
-
-        final Authorizations authorizations = element.getValue();
-
-        if (authorizations.getUsers() == null) {
-            authorizations.setUsers(new Users());
-        }
-        if (authorizations.getGroups() == null) {
-            authorizations.setGroups(new Groups());
-        }
+        final Authorizations authorizations = unmarshallAuthorizations();
         if (authorizations.getPolicies() == null) {
             authorizations.setPolicies(new Policies());
         }
 
-        final AuthorizationsHolder authorizationsHolder = new 
AuthorizationsHolder(authorizations);
+        final Tenants tenants = unmarshallTenants();
+        if (tenants.getUsers() == null) {
+            tenants.setUsers(new Users());
+        }
+        if (tenants.getGroups() == null) {
+            tenants.setGroups(new Groups());
+        }
+
+        final AuthorizationsHolder authorizationsHolder = new 
AuthorizationsHolder(authorizations, tenants);
         final boolean emptyAuthorizations = 
authorizationsHolder.getAllUsers().isEmpty() && 
authorizationsHolder.getAllPolicies().isEmpty();
         final boolean hasInitialAdminIdentity = (initialAdminIdentity != null 
&& !StringUtils.isBlank(initialAdminIdentity));
         final boolean hasLegacyAuthorizedUsers = (legacyAuthorizedUsersFile != 
null && !StringUtils.isBlank(legacyAuthorizedUsersFile));
@@ -236,21 +269,37 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                 throw new AuthorizerCreationException("Cannot provide an 
Initial Admin Identity and a Legacy Authorized Users File");
             } else if (hasInitialAdminIdentity) {
                 logger.info("Populating authorizations for Initial Admin: " + 
initialAdminIdentity);
-                populateInitialAdmin(authorizations);
+                populateInitialAdmin(authorizations, tenants);
             } else if (hasLegacyAuthorizedUsers) {
                 logger.info("Converting " + legacyAuthorizedUsersFile + " to 
new authorizations model");
-                convertLegacyAuthorizedUsers(authorizations);
+                convertLegacyAuthorizedUsers(authorizations, tenants);
             }
 
-            populateNodes(authorizations);
+            populateNodes(authorizations, tenants);
 
             // save any changes that were made and repopulate the holder
-            saveAndRefreshHolder(authorizations);
+            saveAndRefreshHolder(authorizations, tenants);
         } else {
             this.authorizationsHolder.set(authorizationsHolder);
         }
     }
 
+    private Authorizations unmarshallAuthorizations() throws JAXBException {
+        final Unmarshaller unmarshaller = 
JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
+        unmarshaller.setSchema(authorizationsSchema);
+
+        final JAXBElement<Authorizations> element = unmarshaller.unmarshal(new 
StreamSource(authorizationsFile), Authorizations.class);
+        return element.getValue();
+    }
+
+    private Tenants unmarshallTenants() throws JAXBException {
+        final Unmarshaller unmarshaller = 
JAXB_TENANTS_CONTEXT.createUnmarshaller();
+        unmarshaller.setSchema(tenantsSchema);
+
+        final JAXBElement<Tenants> element = unmarshaller.unmarshal(new 
StreamSource(tenantsFile), Tenants.class);
+        return element.getValue();
+    }
+
     /**
      * Try to parse the flow configuration file to extract the root group id 
and port information.
      *
@@ -269,13 +318,13 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     /**
      *  Creates the initial admin user and policies for access the flow and 
managing users and policies.
      */
-    private void populateInitialAdmin(final Authorizations authorizations) {
+    private void populateInitialAdmin(final Authorizations authorizations, 
Tenants tenants) {
         // generate an identifier and add a User with the given identifier and 
identity
         final UUID adminIdentifier = 
UUID.nameUUIDFromBytes(initialAdminIdentity.getBytes(StandardCharsets.UTF_8));
         final User adminUser = new 
User.Builder().identifier(adminIdentifier.toString()).identity(initialAdminIdentity).build();
 
-        final org.apache.nifi.authorization.file.generated.User jaxbAdminUser 
= createJAXBUser(adminUser);
-        authorizations.getUsers().getUser().add(jaxbAdminUser);
+        final org.apache.nifi.authorization.file.tenants.generated.User 
jaxbAdminUser = createJAXBUser(adminUser);
+        tenants.getUsers().getUser().add(jaxbAdminUser);
 
         // grant the user read access to the /flow resource
         addAccessPolicy(authorizations, ResourceType.Flow.getValue(), 
adminUser.getIdentifier(), READ_CODE);
@@ -307,11 +356,11 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
      *
      * @param authorizations the overall authorizations
      */
-    private void populateNodes(Authorizations authorizations) {
+    private void populateNodes(Authorizations authorizations, Tenants tenants) 
{
         for (String nodeIdentity : nodeIdentities) {
             // see if we have an existing user for the given node identity
-            org.apache.nifi.authorization.file.generated.User jaxbNodeUser = 
null;
-            for (org.apache.nifi.authorization.file.generated.User user : 
authorizations.getUsers().getUser()) {
+            org.apache.nifi.authorization.file.tenants.generated.User 
jaxbNodeUser = null;
+            for (org.apache.nifi.authorization.file.tenants.generated.User 
user : tenants.getUsers().getUser()) {
                 if (user.getIdentity().equals(nodeIdentity)) {
                     jaxbNodeUser = user;
                     break;
@@ -325,7 +374,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                 final User nodeUser = new 
User.Builder().identifier(nodeIdentifier.toString()).identity(nodeIdentity).build();
 
                 jaxbNodeUser = createJAXBUser(nodeUser);
-                authorizations.getUsers().getUser().add(jaxbNodeUser);
+                tenants.getUsers().getUser().add(jaxbNodeUser);
             }
 
             // grant access to the proxy resource
@@ -343,11 +392,12 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     /**
      * Unmarshalls an existing authorized-users.xml and converts the object 
model to the new model.
      *
-     * @param authorizations the current Authorizations instance that users, 
groups, and policies will be added to
+     * @param authorizations the current Authorizations instance that policies 
will be added to
+     * @param tenants the current Tenants instance users and groups will be 
added to
      * @throws AuthorizerCreationException if the legacy authorized users file 
that was provided does not exist
      * @throws JAXBException if the legacy authorized users file that was 
provided could not be unmarshalled
      */
-    private void convertLegacyAuthorizedUsers(final Authorizations 
authorizations) throws AuthorizerCreationException, JAXBException {
+    private void convertLegacyAuthorizedUsers(final Authorizations 
authorizations, final Tenants tenants) throws AuthorizerCreationException, 
JAXBException {
         final File authorizedUsersFile = new File(legacyAuthorizedUsersFile);
         if (!authorizedUsersFile.exists()) {
             throw new AuthorizerCreationException("Legacy Authorized Users 
File '" + legacyAuthorizedUsersFile + "' does not exists");
@@ -386,15 +436,15 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             final String userIdentifier = 
UUID.nameUUIDFromBytes(legacyUserDn.getBytes(StandardCharsets.UTF_8)).toString();
 
             // create the new User and add it to the list of users
-            org.apache.nifi.authorization.file.generated.User user = new 
org.apache.nifi.authorization.file.generated.User();
+            org.apache.nifi.authorization.file.tenants.generated.User user = 
new org.apache.nifi.authorization.file.tenants.generated.User();
             user.setIdentifier(userIdentifier);
             user.setIdentity(legacyUserDn);
-            authorizations.getUsers().getUser().add(user);
+            tenants.getUsers().getUser().add(user);
 
             // if there was a group name find or create the group and add the 
user to it
-            org.apache.nifi.authorization.file.generated.Group group = 
getOrCreateGroup(authorizations, legacyUser.getGroup());
+            org.apache.nifi.authorization.file.tenants.generated.Group group = 
getOrCreateGroup(tenants, legacyUser.getGroup());
             if (group != null) {
-                org.apache.nifi.authorization.file.generated.Group.User 
groupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+                
org.apache.nifi.authorization.file.tenants.generated.Group.User groupUser = new 
org.apache.nifi.authorization.file.tenants.generated.Group.User();
                 groupUser.setIdentifier(userIdentifier);
                 group.getUser().add(groupUser);
             }
@@ -431,8 +481,8 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                     final String mappedUserAccessControl = 
IdentityMappingUtil.mapIdentity(userAccessControl, identityMappings);
 
                     // find a user where the identity is the userAccessControl
-                    org.apache.nifi.authorization.file.generated.User 
foundUser = null;
-                    for (org.apache.nifi.authorization.file.generated.User 
jaxbUser : authorizations.getUsers().getUser()) {
+                    org.apache.nifi.authorization.file.tenants.generated.User 
foundUser = null;
+                    for 
(org.apache.nifi.authorization.file.tenants.generated.User jaxbUser : 
tenants.getUsers().getUser()) {
                         if 
(jaxbUser.getIdentity().equals(mappedUserAccessControl)) {
                             foundUser = jaxbUser;
                             break;
@@ -442,7 +492,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
                     // couldn't find the user matching the access control so 
log a warning and skip
                     if (foundUser == null) {
                         logger.warn("Found port with user access control for 
{} but no user exists with this identity, skipping...",
-                                new Object[] {userAccessControl});
+                                new Object[] {mappedUserAccessControl});
                         continue;
                     }
 
@@ -460,8 +510,8 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             if (portDTO.getGroupAccessControl() != null) {
                 for (String groupAccessControl : 
portDTO.getGroupAccessControl()) {
                     // find a group where the name is the groupAccessControl
-                    org.apache.nifi.authorization.file.generated.Group 
foundGroup = null;
-                    for (org.apache.nifi.authorization.file.generated.Group 
jaxbGroup : authorizations.getGroups().getGroup()) {
+                    org.apache.nifi.authorization.file.tenants.generated.Group 
foundGroup = null;
+                    for 
(org.apache.nifi.authorization.file.tenants.generated.Group jaxbGroup : 
tenants.getGroups().getGroup()) {
                         if (jaxbGroup.getName().equals(groupAccessControl)) {
                             foundGroup = jaxbGroup;
                             break;
@@ -541,17 +591,17 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
     /**
      * Finds the Group with the given name, or creates a new one and adds it 
to Authorizations.
      *
-     * @param authorizations the Authorizations reference
+     * @param tenants the Authorizations reference
      * @param groupName the name of the group to look for
      * @return the Group from Authorizations with the given name, or a new 
instance
      */
-    private org.apache.nifi.authorization.file.generated.Group 
getOrCreateGroup(final Authorizations authorizations, final String groupName) {
+    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.generated.Group foundGroup = null;
-        for (org.apache.nifi.authorization.file.generated.Group group : 
authorizations.getGroups().getGroup()) {
+        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;
@@ -560,10 +610,10 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
 
         if (foundGroup == null) {
             UUID newGroupIdentifier = 
UUID.nameUUIDFromBytes(groupName.getBytes(StandardCharsets.UTF_8));
-            foundGroup = new 
org.apache.nifi.authorization.file.generated.Group();
+            foundGroup = new 
org.apache.nifi.authorization.file.tenants.generated.Group();
             foundGroup.setIdentifier(newGroupIdentifier.toString());
             foundGroup.setName(groupName);
-            authorizations.getGroups().getGroup().add(foundGroup);
+            tenants.getGroups().getGroup().add(foundGroup);
         }
 
         return foundGroup;
@@ -659,22 +709,36 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
      * Synchronized to ensure only one thread writes the file at a time.
      *
      * @param authorizations the authorizations to save and populate from
+     * @param tenants the tenants to save and populate from
      * @throws AuthorizationAccessException if an error occurs saving the 
authorizations
      */
-    private synchronized void saveAndRefreshHolder(final Authorizations 
authorizations) throws AuthorizationAccessException {
+    private synchronized void saveAndRefreshHolder(final Authorizations 
authorizations, final Tenants tenants) throws AuthorizationAccessException {
         try {
-            final Marshaller marshaller = 
JAXB_AUTHORIZATIONS_CONTEXT.createMarshaller();
-            marshaller.setSchema(authorizationsSchema);
-            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
-            marshaller.marshal(authorizations, authorizationsFile);
+            saveTenants(tenants);
+            saveAuthorizations(authorizations);
 
-            final AuthorizationsHolder authorizationsHolder = new 
AuthorizationsHolder(authorizations);
+            final AuthorizationsHolder authorizationsHolder = new 
AuthorizationsHolder(authorizations, tenants);
             this.authorizationsHolder.set(authorizationsHolder);
         } catch (JAXBException e) {
             throw new AuthorizationAccessException("Unable to save 
Authorizations", e);
         }
     }
 
+    private void saveAuthorizations(final Authorizations authorizations) 
throws JAXBException {
+        final Marshaller marshaller = 
JAXB_AUTHORIZATIONS_CONTEXT.createMarshaller();
+        marshaller.setSchema(authorizationsSchema);
+        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+        marshaller.marshal(authorizations, authorizationsFile);
+    }
+
+    private void saveTenants(final Tenants tenants) throws JAXBException {
+        final Marshaller marshaller = JAXB_TENANTS_CONTEXT.createMarshaller();
+        marshaller.setSchema(tenantsSchema);
+        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+        marshaller.marshal(tenants, tenantsFile);
+    }
+
+
     @AuthorizerContext
     public void setNiFiProperties(NiFiProperties properties) {
         this.properties = properties;
@@ -693,28 +757,29 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("Group cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
 
         // determine that all users in the group exist before doing anything, 
throw an exception if they don't
-        final Set<org.apache.nifi.authorization.file.generated.User> jaxbUsers 
= checkGroupUsers(group, authorizations.getUsers().getUser());
+        final Set<org.apache.nifi.authorization.file.tenants.generated.User> 
jaxbUsers = checkGroupUsers(group, tenants.getUsers().getUser());
 
         // create a new JAXB Group based on the incoming Group
-        final org.apache.nifi.authorization.file.generated.Group jaxbGroup = 
new org.apache.nifi.authorization.file.generated.Group();
+        final org.apache.nifi.authorization.file.tenants.generated.Group 
jaxbGroup = new org.apache.nifi.authorization.file.tenants.generated.Group();
         jaxbGroup.setIdentifier(group.getIdentifier());
         jaxbGroup.setName(group.getName());
 
         // add each user to the group
         for (String groupUser : group.getUsers()) {
-            org.apache.nifi.authorization.file.generated.Group.User 
jaxbGroupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+            org.apache.nifi.authorization.file.tenants.generated.Group.User 
jaxbGroupUser = new 
org.apache.nifi.authorization.file.tenants.generated.Group.User();
             jaxbGroupUser.setIdentifier(groupUser);
             jaxbGroup.getUser().add(jaxbGroupUser);
         }
 
-        authorizations.getGroups().getGroup().add(jaxbGroup);
-        saveAndRefreshHolder(authorizations);
+        tenants.getGroups().getGroup().add(jaxbGroup);
+        saveAndRefreshHolder(authorizations, tenants);
 
-        final AuthorizationsHolder holder = this.authorizationsHolder.get();
-        return holder.getGroupsById().get(group.getIdentifier());
+        return 
this.authorizationsHolder.get().getGroupsById().get(group.getIdentifier());
     }
 
     @Override
@@ -731,11 +796,13 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("Group cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
 
         // find the group that needs to be update
-        org.apache.nifi.authorization.file.generated.Group updateGroup = null;
-        for (org.apache.nifi.authorization.file.generated.Group jaxbGroup : 
authorizations.getGroups().getGroup()) {
+        org.apache.nifi.authorization.file.tenants.generated.Group updateGroup 
= null;
+        for (org.apache.nifi.authorization.file.tenants.generated.Group 
jaxbGroup : tenants.getGroups().getGroup()) {
             if (jaxbGroup.getIdentifier().equals(group.getIdentifier())) {
                 updateGroup = jaxbGroup;
                 break;
@@ -750,22 +817,24 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
         // reset the list of users and add each user to the group
         updateGroup.getUser().clear();
         for (String groupUser : group.getUsers()) {
-            org.apache.nifi.authorization.file.generated.Group.User 
jaxbGroupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+            org.apache.nifi.authorization.file.tenants.generated.Group.User 
jaxbGroupUser = new 
org.apache.nifi.authorization.file.tenants.generated.Group.User();
             jaxbGroupUser.setIdentifier(groupUser);
             updateGroup.getUser().add(jaxbGroupUser);
         }
 
         updateGroup.setName(group.getName());
-        saveAndRefreshHolder(authorizations);
+        saveAndRefreshHolder(authorizations, tenants);
 
-        final AuthorizationsHolder holder = this.authorizationsHolder.get();
-        return holder.getGroupsById().get(group.getIdentifier());
+        return 
this.authorizationsHolder.get().getGroupsById().get(group.getIdentifier());
     }
 
     @Override
     public synchronized Group deleteGroup(Group group) throws 
AuthorizationAccessException {
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
-        final List<org.apache.nifi.authorization.file.generated.Group> groups 
= authorizations.getGroups().getGroup();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
+
+        final List<org.apache.nifi.authorization.file.tenants.generated.Group> 
groups = tenants.getGroups().getGroup();
 
         // for each policy iterate over the group reference and remove the 
group reference if it matches the group being deleted
         for (Policy policy : authorizations.getPolicies().getPolicy()) {
@@ -781,9 +850,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
 
         // now remove the actual group from the top-level list of groups
         boolean removedGroup = false;
-        Iterator<org.apache.nifi.authorization.file.generated.Group> iter = 
groups.iterator();
+        Iterator<org.apache.nifi.authorization.file.tenants.generated.Group> 
iter = groups.iterator();
         while (iter.hasNext()) {
-            org.apache.nifi.authorization.file.generated.Group jaxbGroup = 
iter.next();
+            org.apache.nifi.authorization.file.tenants.generated.Group 
jaxbGroup = iter.next();
             if (group.getIdentifier().equals(jaxbGroup.getIdentifier())) {
                 iter.remove();
                 removedGroup = true;
@@ -792,7 +861,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
         }
 
         if (removedGroup) {
-            saveAndRefreshHolder(authorizations);
+            saveAndRefreshHolder(authorizations, tenants);
             return group;
         } else {
             return null;
@@ -804,11 +873,11 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
         return authorizationsHolder.get().getAllGroups();
     }
 
-    private Set<org.apache.nifi.authorization.file.generated.User> 
checkGroupUsers(final Group group, final 
List<org.apache.nifi.authorization.file.generated.User> users) {
-        final Set<org.apache.nifi.authorization.file.generated.User> jaxbUsers 
= new HashSet<>();
+    private Set<org.apache.nifi.authorization.file.tenants.generated.User> 
checkGroupUsers(final Group group, final 
List<org.apache.nifi.authorization.file.tenants.generated.User> users) {
+        final Set<org.apache.nifi.authorization.file.tenants.generated.User> 
jaxbUsers = new HashSet<>();
         for (String groupUser : group.getUsers()) {
             boolean found = false;
-            for (org.apache.nifi.authorization.file.generated.User jaxbUser : 
users) {
+            for (org.apache.nifi.authorization.file.tenants.generated.User 
jaxbUser : users) {
                 if (jaxbUser.getIdentifier().equals(groupUser)) {
                     jaxbUsers.add(jaxbUser);
                     found = true;
@@ -831,19 +900,20 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("User cannot be null");
         }
 
-        final org.apache.nifi.authorization.file.generated.User jaxbUser = 
createJAXBUser(user);
+        final org.apache.nifi.authorization.file.tenants.generated.User 
jaxbUser = createJAXBUser(user);
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
-        authorizations.getUsers().getUser().add(jaxbUser);
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
+        tenants.getUsers().getUser().add(jaxbUser);
 
-        saveAndRefreshHolder(authorizations);
+        saveAndRefreshHolder(authorizations, tenants);
 
-        final AuthorizationsHolder holder = authorizationsHolder.get();
-        return holder.getUsersById().get(user.getIdentifier());
+        return 
this.authorizationsHolder.get().getUsersById().get(user.getIdentifier());
     }
 
-    private org.apache.nifi.authorization.file.generated.User 
createJAXBUser(User user) {
-        final org.apache.nifi.authorization.file.generated.User jaxbUser = new 
org.apache.nifi.authorization.file.generated.User();
+    private org.apache.nifi.authorization.file.tenants.generated.User 
createJAXBUser(User user) {
+        final org.apache.nifi.authorization.file.tenants.generated.User 
jaxbUser = new org.apache.nifi.authorization.file.tenants.generated.User();
         jaxbUser.setIdentifier(user.getIdentifier());
         jaxbUser.setIdentity(user.getIdentity());
         return jaxbUser;
@@ -875,12 +945,15 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("User cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
-        final List<org.apache.nifi.authorization.file.generated.User> users = 
authorizations.getUsers().getUser();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
+
+        final List<org.apache.nifi.authorization.file.tenants.generated.User> 
users = tenants.getUsers().getUser();
 
         // fine the User that needs to be updated
-        org.apache.nifi.authorization.file.generated.User updateUser = null;
-        for (org.apache.nifi.authorization.file.generated.User jaxbUser : 
users) {
+        org.apache.nifi.authorization.file.tenants.generated.User updateUser = 
null;
+        for (org.apache.nifi.authorization.file.tenants.generated.User 
jaxbUser : users) {
             if (user.getIdentifier().equals(jaxbUser.getIdentifier())) {
                 updateUser = jaxbUser;
                 break;
@@ -892,10 +965,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             return null;
         } else {
             updateUser.setIdentity(user.getIdentity());
-            saveAndRefreshHolder(authorizations);
+            saveAndRefreshHolder(authorizations, tenants);
 
-            final AuthorizationsHolder holder = authorizationsHolder.get();
-            return holder.getUsersById().get(user.getIdentifier());
+            return 
this.authorizationsHolder.get().getUsersById().get(user.getIdentifier());
         }
     }
 
@@ -905,14 +977,17 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("User cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
-        final List<org.apache.nifi.authorization.file.generated.User> users = 
authorizations.getUsers().getUser();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
+
+        final List<org.apache.nifi.authorization.file.tenants.generated.User> 
users = tenants.getUsers().getUser();
 
         // for each group iterate over the user references and remove the user 
reference if it matches the user being deleted
-        for (org.apache.nifi.authorization.file.generated.Group group : 
authorizations.getGroups().getGroup()) {
-            Iterator<org.apache.nifi.authorization.file.generated.Group.User> 
groupUserIter = group.getUser().iterator();
+        for (org.apache.nifi.authorization.file.tenants.generated.Group group 
: tenants.getGroups().getGroup()) {
+            
Iterator<org.apache.nifi.authorization.file.tenants.generated.Group.User> 
groupUserIter = group.getUser().iterator();
             while (groupUserIter.hasNext()) {
-                org.apache.nifi.authorization.file.generated.Group.User 
groupUser = groupUserIter.next();
+                
org.apache.nifi.authorization.file.tenants.generated.Group.User groupUser = 
groupUserIter.next();
                 if (groupUser.getIdentifier().equals(user.getIdentifier())) {
                     groupUserIter.remove();
                     break;
@@ -934,9 +1009,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
 
         // remove the actual user if it exists
         boolean removedUser = false;
-        Iterator<org.apache.nifi.authorization.file.generated.User> iter = 
users.iterator();
+        Iterator<org.apache.nifi.authorization.file.tenants.generated.User> 
iter = users.iterator();
         while (iter.hasNext()) {
-            org.apache.nifi.authorization.file.generated.User jaxbUser = 
iter.next();
+            org.apache.nifi.authorization.file.tenants.generated.User jaxbUser 
= iter.next();
             if (user.getIdentifier().equals(jaxbUser.getIdentifier())) {
                 iter.remove();
                 removedUser = true;
@@ -945,7 +1020,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
         }
 
         if (removedUser) {
-            saveAndRefreshHolder(authorizations);
+            saveAndRefreshHolder(authorizations, tenants);
             return user;
         } else {
             return null;
@@ -969,13 +1044,14 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
         final Policy policy = createJAXBPolicy(accessPolicy);
 
         // add the new Policy to the top-level list of policies
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
         authorizations.getPolicies().getPolicy().add(policy);
 
-        saveAndRefreshHolder(authorizations);
+        saveAndRefreshHolder(authorizations, tenants);
 
-        final AuthorizationsHolder holder = authorizationsHolder.get();
-        return holder.getPoliciesById().get(accessPolicy.getIdentifier());
+        return 
this.authorizationsHolder.get().getPoliciesById().get(accessPolicy.getIdentifier());
     }
 
     private Policy createJAXBPolicy(final AccessPolicy accessPolicy) {
@@ -1014,7 +1090,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("AccessPolicy cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
 
         // try to find an existing Authorization that matches the policy id
         Policy updatePolicy = null;
@@ -1032,10 +1110,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
 
         // update the Policy, save, reload, and return
         transferUsersAndGroups(accessPolicy, updatePolicy);
-        saveAndRefreshHolder(authorizations);
+        saveAndRefreshHolder(authorizations, tenants);
 
-        final AuthorizationsHolder holder = authorizationsHolder.get();
-        return holder.getPoliciesById().get(accessPolicy.getIdentifier());
+        return 
this.authorizationsHolder.get().getPoliciesById().get(accessPolicy.getIdentifier());
     }
 
     @Override
@@ -1044,7 +1121,9 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             throw new IllegalArgumentException("AccessPolicy cannot be null");
         }
 
-        final Authorizations authorizations = 
this.authorizationsHolder.get().getAuthorizations();
+        final AuthorizationsHolder holder = this.authorizationsHolder.get();
+        final Tenants tenants = holder.getTenants();
+        final Authorizations authorizations = holder.getAuthorizations();
 
         // find the matching Policy and remove it
         boolean deletedPolicy = false;
@@ -1063,7 +1142,7 @@ public class FileAuthorizer extends 
AbstractPolicyBasedAuthorizer {
             return null;
         }
 
-        saveAndRefreshHolder(authorizations);
+        saveAndRefreshHolder(authorizations, tenants);
         return accessPolicy;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
index 452af96..0ab27a9 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
@@ -15,75 +15,6 @@
 -->
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";>
 
-    <!-- group -->
-    <xs:complexType name="Group">
-        <xs:sequence>
-            <xs:element name="user" minOccurs="0" maxOccurs="unbounded" >
-                <xs:complexType>
-                    <xs:attribute name="identifier">
-                        <xs:simpleType>
-                            <xs:restriction base="xs:string">
-                                <xs:minLength value="1"/>
-                                <xs:pattern value=".*[^\s].*"/>
-                            </xs:restriction>
-                        </xs:simpleType>
-                    </xs:attribute>
-                </xs:complexType>
-            </xs:element>
-        </xs:sequence>
-        <xs:attribute name="identifier">
-            <xs:simpleType>
-                <xs:restriction base="xs:string">
-                    <xs:minLength value="1"/>
-                    <xs:pattern value=".*[^\s].*"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute name="name">
-            <xs:simpleType>
-                <xs:restriction base="xs:string">
-                    <xs:minLength value="1"/>
-                    <xs:pattern value=".*[^\s].*"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-    </xs:complexType>
-
-    <!-- groups -->
-    <xs:complexType name="Groups">
-        <xs:sequence>
-            <xs:element name="group" type="Group" minOccurs="0" 
maxOccurs="unbounded"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- user -->
-    <xs:complexType name="User">
-        <xs:attribute name="identifier">
-            <xs:simpleType>
-                <xs:restriction base="xs:string">
-                    <xs:minLength value="1"/>
-                    <xs:pattern value=".*[^\s].*"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute name="identity">
-            <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:complexType name="Users">
-        <xs:sequence>
-            <xs:element name="user" type="User" minOccurs="0" 
maxOccurs="unbounded"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- authorization -->
     <xs:complexType name="Policy">
         <xs:sequence>
             <xs:element name="group" minOccurs="0" maxOccurs="unbounded" >
@@ -137,7 +68,6 @@
         </xs:attribute>
     </xs:complexType>
 
-    <!-- resources -->
     <xs:complexType name="Policies">
         <xs:sequence>
             <xs:element name="policy" type="Policy" minOccurs="0" 
maxOccurs="unbounded"/>
@@ -148,8 +78,6 @@
     <xs:element name="authorizations">
         <xs:complexType>
             <xs:sequence>
-                <xs:element name="groups" type="Groups" minOccurs="0" 
maxOccurs="1" />
-                <xs:element name="users" type="Users" minOccurs="0" 
maxOccurs="1" />
                 <xs:element name="policies" type="Policies" minOccurs="0" 
maxOccurs="1" />
             </xs:sequence>
         </xs:complexType>

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/legacy-users.xsd
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/legacy-users.xsd
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/legacy-users.xsd
new file mode 100644
index 0000000..4ee1e17
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/legacy-users.xsd
@@ -0,0 +1,64 @@
+<?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>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/tenants.xsd
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/tenants.xsd
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/tenants.xsd
new file mode 100644
index 0000000..c1193c3
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/tenants.xsd
@@ -0,0 +1,96 @@
+<?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";>
+
+    <!-- group -->
+    <xs:complexType name="Group">
+        <xs:sequence>
+            <xs:element name="user" minOccurs="0" maxOccurs="unbounded" >
+                <xs:complexType>
+                    <xs:attribute name="identifier">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:minLength value="1"/>
+                                <xs:pattern value=".*[^\s].*"/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+        <xs:attribute name="identifier">
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:minLength value="1"/>
+                    <xs:pattern value=".*[^\s].*"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+        <xs:attribute name="name">
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:minLength value="1"/>
+                    <xs:pattern value=".*[^\s].*"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+    </xs:complexType>
+
+    <!-- groups -->
+    <xs:complexType name="Groups">
+        <xs:sequence>
+            <xs:element name="group" type="Group" minOccurs="0" 
maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- user -->
+    <xs:complexType name="User">
+        <xs:attribute name="identifier">
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:minLength value="1"/>
+                    <xs:pattern value=".*[^\s].*"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+        <xs:attribute name="identity">
+            <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:complexType name="Users">
+        <xs:sequence>
+            <xs:element name="user" type="User" minOccurs="0" 
maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- top-level authorizations element -->
+    <xs:element name="tenants">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="groups" type="Groups" minOccurs="0" 
maxOccurs="1" />
+                <xs:element name="users" type="Users" minOccurs="0" 
maxOccurs="1" />
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+
+</xs:schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/5e4ba045/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/users.xsd
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/users.xsd
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/users.xsd
deleted file mode 100644
index 4ee1e17..0000000
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/users.xsd
+++ /dev/null
@@ -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>
\ No newline at end of file

Reply via email to