You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2016/07/06 20:57:08 UTC

[2/2] nifi git commit: NIFI-2171 Removing list of groups from User - Making FileAuthorizer not update the resource or action when updating an AccessPolicy - Adding corresponding READ policies during initial seeding and legacy conversions - Adding checks

NIFI-2171 Removing list of groups from User
- Making FileAuthorizer not update the resource or action when updating an AccessPolicy
- Adding corresponding READ policies during initial seeding and legacy conversions
- Adding checks to FileAuthorizer to ensure only one policy per resource-action
- Removing merging of policies on legacy conversion since we have one action per policy now
- This closes #608


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

Branch: refs/heads/master
Commit: c5889314ca2d2c936145b2a51c29c55dd4d94fd5
Parents: f4c94e3
Author: Bryan Bende <bb...@apache.org>
Authored: Tue Jul 5 16:16:08 2016 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Wed Jul 6 16:56:07 2016 -0400

----------------------------------------------------------------------
 .../AbstractPolicyBasedAuthorizer.java          | 108 +++++++---
 .../org/apache/nifi/authorization/User.java     |  78 -------
 .../authorization/UsersAndAccessPolicies.java   |   8 +
 .../TestAbstractPolicyBasedAuthorizer.java      |  29 ++-
 .../org/apache/nifi/authorization/TestUser.java |  85 --------
 .../authorization/AuthorizerFactoryBean.java    |   4 +-
 .../authorization/AuthorizationsHolder.java     |  77 ++++---
 .../nifi/authorization/FileAuthorizer.java      | 216 +++++--------------
 .../nifi/authorization/RoleAccessPolicy.java    |  19 +-
 .../src/main/xsd/authorizations.xsd             |  28 +--
 .../nifi/authorization/FileAuthorizerTest.java  |  96 +++------
 .../nifi/controller/TestFlowController.java     |  10 +-
 .../nifi/web/StandardNiFiServiceFacade.java     |  33 ++-
 .../org/apache/nifi/web/dao/UserGroupDAO.java   |   8 +
 .../impl/StandardPolicyBasedAuthorizerDAO.java  |  15 +-
 .../StandardPolicyBasedAuthorizerDAOSpec.groovy |  28 +--
 16 files changed, 311 insertions(+), 531 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
index 6a8467d..b173155 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
@@ -17,6 +17,7 @@
 package org.apache.nifi.authorization;
 
 import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -48,7 +49,7 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
     static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
 
     static final String USER_ELEMENT = "user";
-    static final String USER_GROUP_ELEMENT = "userGroup";
+    static final String GROUP_USER_ELEMENT = "groupUser";
     static final String GROUP_ELEMENT = "group";
     static final String POLICY_ELEMENT = "policy";
     static final String POLICY_USER_ELEMENT = "policyUser";
@@ -62,6 +63,44 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
     public static final String EMPTY_FINGERPRINT = "EMPTY";
 
     @Override
+    public final void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+        doOnConfigured(configurationContext);
+
+        // ensure that only one policy per resource-action exists
+        for (AccessPolicy accessPolicy : getAccessPolicies()) {
+            if (policyExists(accessPolicy)) {
+                throw new AuthorizerCreationException("Found multiple policies for " + accessPolicy.getResource()
+                        + " with " + accessPolicy.getAction());
+            }
+        }
+    }
+
+    /**
+     * Allows sub-classes to take action when onConfigured is called.
+     *
+     * @param configurationContext the configuration context
+     * @throws AuthorizerCreationException if an error occurs during onConfigured process
+     */
+    protected abstract void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException;
+
+    /**
+     * Checks if another policy exists with the same resource and action as the given policy.
+     *
+     * @param checkAccessPolicy an access policy being checked
+     * @return true if another access policy exists with the same resource and action, false otherwise
+     */
+    private boolean policyExists(final AccessPolicy checkAccessPolicy) {
+        for (AccessPolicy accessPolicy : getAccessPolicies()) {
+            if (!accessPolicy.getIdentifier().equals(checkAccessPolicy.getIdentifier())
+                    && accessPolicy.getResource().equals(checkAccessPolicy.getResource())
+                    && accessPolicy.getAction().equals(checkAccessPolicy.getAction())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
     public final AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException {
         final UsersAndAccessPolicies usersAndAccessPolicies = getUsersAndAccessPolicies();
         final String resourceIdentifier = request.getResource().getIdentifier();
@@ -77,9 +116,11 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
             return AuthorizationResult.denied("Unknown user with identity " + request.getIdentity());
         }
 
+        final Set<Group> userGroups = usersAndAccessPolicies.getGroups(user.getIdentity());
+
         for (AccessPolicy policy : policies) {
             final boolean containsUser = policy.getUsers().contains(user.getIdentifier());
-            if (policy.getAction() == request.getAction() && (containsUser || containsGroup(user, policy)) ) {
+            if (policy.getAction() == request.getAction() && (containsUser || containsGroup(userGroups, policy)) ) {
                 return AuthorizationResult.approved();
             }
         }
@@ -88,13 +129,13 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
     }
 
 
-    private boolean containsGroup(final User user, final AccessPolicy policy) {
-        if (user.getGroups().isEmpty() || policy.getGroups().isEmpty()) {
+    private boolean containsGroup(Set<Group> userGroups, final AccessPolicy policy) {
+        if (userGroups.isEmpty() || policy.getGroups().isEmpty()) {
             return false;
         }
 
-        for (String userGroup : user.getGroups()) {
-            if (policy.getGroups().contains(userGroup)) {
+        for (Group userGroup : userGroups) {
+            if (policy.getGroups().contains(userGroup.getIdentifier())) {
                 return true;
             }
         }
@@ -200,6 +241,20 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
      */
     public abstract Set<User> getUsers() throws AuthorizationAccessException;
 
+    /**
+     * Adds the given policy ensuring that multiple policies can not be added for the same resource and action.
+     *
+     * @param accessPolicy the policy to add
+     * @return the policy that was added
+     * @throws AuthorizationAccessException if there was an unexpected error performing the operation
+     */
+    public final synchronized AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+        if (policyExists(accessPolicy)) {
+            throw new IllegalStateException("Found multiple policies for " + accessPolicy.getResource()
+                    + " with " + accessPolicy.getAction());
+        }
+        return doAddAccessPolicy(accessPolicy);
+    }
 
     /**
      * Adds the given policy.
@@ -208,7 +263,7 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
      * @return the policy that was added
      * @throws AuthorizationAccessException if there was an unexpected error performing the operation
      */
-    public abstract AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException;
+    protected abstract AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException;
 
     /**
      * Retrieves the policy with the given identifier.
@@ -304,20 +359,21 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
                 .identifier(element.getAttribute(IDENTIFIER_ATTR))
                 .identity(element.getAttribute(IDENTITY_ATTR));
 
-        NodeList userGroups = element.getElementsByTagName(USER_GROUP_ELEMENT);
-        for (int i=0; i < userGroups.getLength(); i++) {
-            Element userGroupNode = (Element) userGroups.item(i);
-            builder.addGroup(userGroupNode.getAttribute(IDENTIFIER_ATTR));
-        }
-
         return builder.build();
     }
 
     private Group parseGroup(final Element element) {
-        return new Group.Builder()
+        final Group.Builder builder = new Group.Builder()
                 .identifier(element.getAttribute(IDENTIFIER_ATTR))
-                .name(element.getAttribute(NAME_ATTR))
-                .build();
+                .name(element.getAttribute(NAME_ATTR));
+
+        NodeList groupUsers = element.getElementsByTagName(GROUP_USER_ELEMENT);
+        for (int i=0; i < groupUsers.getLength(); i++) {
+            Element groupUserNode = (Element) groupUsers.item(i);
+            builder.addUser(groupUserNode.getAttribute(IDENTIFIER_ATTR));
+        }
+
+        return builder.build();
     }
 
     private AccessPolicy parsePolicy(final Element element) {
@@ -403,26 +459,26 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
     }
 
     private void writeUser(final XMLStreamWriter writer, final User user) throws XMLStreamException {
-        List<String> userGroups = new ArrayList<>(user.getGroups());
-        Collections.sort(userGroups);
-
         writer.writeStartElement(USER_ELEMENT);
         writer.writeAttribute(IDENTIFIER_ATTR, user.getIdentifier());
         writer.writeAttribute(IDENTITY_ATTR, user.getIdentity());
-
-        for (String userGroup : userGroups) {
-            writer.writeStartElement(USER_GROUP_ELEMENT);
-            writer.writeAttribute(IDENTIFIER_ATTR, userGroup);
-            writer.writeEndElement();
-        }
-
         writer.writeEndElement();
     }
 
     private void writeGroup(final XMLStreamWriter writer, final Group group) throws XMLStreamException {
+        List<String> users = new ArrayList<>(group.getUsers());
+        Collections.sort(users);
+
         writer.writeStartElement(GROUP_ELEMENT);
         writer.writeAttribute(IDENTIFIER_ATTR, group.getIdentifier());
         writer.writeAttribute(NAME_ATTR, group.getName());
+
+        for (String user : users) {
+            writer.writeStartElement(GROUP_USER_ELEMENT);
+            writer.writeAttribute(IDENTIFIER_ATTR, user);
+            writer.writeEndElement();
+        }
+
         writer.writeEndElement();
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-api/src/main/java/org/apache/nifi/authorization/User.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/User.java b/nifi-api/src/main/java/org/apache/nifi/authorization/User.java
index 1e62d58..371241b 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/User.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/User.java
@@ -16,10 +16,7 @@
  */
 package org.apache.nifi.authorization;
 
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * A user to create authorization policies for.
@@ -30,12 +27,9 @@ public class User {
 
     private final String identity;
 
-    private final Set<String> groups;
-
     private User(final Builder builder) {
         this.identifier = builder.identifier;
         this.identity = builder.identity;
-        this.groups = Collections.unmodifiableSet(new HashSet<>(builder.groups));
 
         if (identifier == null || identifier.trim().isEmpty()) {
             throw new IllegalArgumentException("Identifier can not be null or empty");
@@ -61,13 +55,6 @@ public class User {
         return identity;
     }
 
-    /**
-     * @return an unmodifiable set of group ids
-     */
-    public Set<String> getGroups() {
-        return groups;
-    }
-
     @Override
     public boolean equals(Object obj) {
         if (obj == null) {
@@ -98,7 +85,6 @@ public class User {
 
         private String identifier;
         private String identity;
-        private Set<String> groups = new HashSet<>();
         private final boolean fromUser;
 
         /**
@@ -122,8 +108,6 @@ public class User {
 
             this.identifier = other.getIdentifier();
             this.identity = other.getIdentity();
-            this.groups.clear();
-            this.groups.addAll(other.getGroups());
             this.fromUser = true;
         }
 
@@ -156,68 +140,6 @@ public class User {
         }
 
         /**
-         * Adds all groups from the provided set to the builder's set of groups.
-         *
-         * @param groups the groups to add
-         * @return the builder
-         */
-        public Builder addGroups(final Set<String> groups) {
-            if (groups != null) {
-                this.groups.addAll(groups);
-            }
-            return this;
-        }
-
-        /**
-         * Adds the provided group to the builder's set of groups.
-         *
-         * @param group the group to add
-         * @return the builder
-         */
-        public Builder addGroup(final String group) {
-            if (group != null) {
-                this.groups.add(group);
-            }
-            return this;
-        }
-
-        /**
-         * Removes all groups in the provided set from the builder's set of groups.
-         *
-         * @param groups the groups to remove
-         * @return the builder
-         */
-        public Builder removeGroups(final Set<String> groups) {
-            if (groups != null) {
-                this.groups.removeAll(groups);
-            }
-            return this;
-        }
-
-        /**
-         * Removes the provided group from the builder's set of groups.
-         *
-         * @param group the group to remove
-         * @return the builder
-         */
-        public Builder removeGroup(final String group) {
-            if (group != null) {
-                this.groups.remove(group);
-            }
-            return this;
-        }
-
-        /**
-         * Clears the builder's set of groups so that groups is non-null with size == 0.
-         *
-         * @return the builder
-         */
-        public Builder clearGroups() {
-            this.groups.clear();
-            return this;
-        }
-
-        /**
          * @return a new User constructed from the state of the builder
          */
         public User build() {

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java b/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
index 9a19977..d7a825c 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
@@ -40,4 +40,12 @@ public interface UsersAndAccessPolicies {
      */
     public User getUser(final String identity);
 
+    /**
+     * Retrieves the groups for a given user identity.
+     *
+     * @param userIdentity a user identity
+     * @return the set of groups for the given user identity
+     */
+    public Set<Group> getGroups(final String userIdentity);
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
index 50f27f3..6be3f1a 100644
--- a/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
@@ -23,6 +23,7 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Set;
@@ -104,11 +105,18 @@ public class TestAbstractPolicyBasedAuthorizer {
         final User user = new User.Builder()
                 .identity(userIdentity)
                 .identifier(userIdentifier)
-                .addGroup(groupIdentifier)
                 .build();
 
         when(usersAndAccessPolicies.getUser(userIdentity)).thenReturn(user);
 
+        final Group group = new Group.Builder()
+                .identifier(groupIdentifier)
+                .name(groupIdentifier)
+                .addUser(user.getIdentifier())
+                .build();
+
+        when(usersAndAccessPolicies.getGroups(userIdentity)).thenReturn(Collections.singleton(group));
+
         final AuthorizationRequest request = new AuthorizationRequest.Builder()
                 .identity(userIdentity)
                 .resource(TEST_RESOURCE)
@@ -180,11 +188,11 @@ public class TestAbstractPolicyBasedAuthorizer {
     public void testGetFingerprint() {
         // create the users, groups, and policies
 
-        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").build();
-        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").build();
+        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build();
+        User user2 = new User.Builder().identifier("user-id-2").identity("user-2").build();
 
-        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").addGroup(group1.getIdentifier()).build();
-        User user2 = new User.Builder().identifier("user-id-2").identity("user-2").addGroup(group2.getIdentifier()).build();
+        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").addUser(user1.getIdentifier()).build();
+        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").addUser(user2.getIdentifier()).build();
 
         AccessPolicy policy1 = new AccessPolicy.Builder()
                 .identifier("policy-id-1")
@@ -251,12 +259,13 @@ public class TestAbstractPolicyBasedAuthorizer {
 
     @Test
     public void testInheritFingerprint() {
-        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").build();
-        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").build();
 
-        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").addGroup(group1.getIdentifier()).build();
+        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build();
         User user2 = new User.Builder().identifier("user-id-2").identity("user-2").build();
 
+        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").addUser(user1.getIdentifier()).build();
+        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").build();
+
         AccessPolicy policy1 = new AccessPolicy.Builder()
                 .identifier("policy-id-1")
                 .resource("resource1")
@@ -392,7 +401,7 @@ public class TestAbstractPolicyBasedAuthorizer {
         }
 
         @Override
-        public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+        protected AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
             policies.add(accessPolicy);
             return accessPolicy;
         }
@@ -428,7 +437,7 @@ public class TestAbstractPolicyBasedAuthorizer {
         }
 
         @Override
-        public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+        public void doOnConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
 
         }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java b/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java
index 483924a..04b1ab1 100644
--- a/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java
@@ -18,12 +18,7 @@ package org.apache.nifi.authorization;
 
 import org.junit.Test;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 public class TestUser {
 
@@ -37,25 +32,16 @@ public class TestUser {
         final User user = new User.Builder()
                 .identifier(identifier)
                 .identity(identity)
-                .addGroup(group1)
-                .addGroup(group2)
                 .build();
 
         assertEquals(identifier, user.getIdentifier());
         assertEquals(identity, user.getIdentity());
-
-        assertNotNull(user.getGroups());
-        assertEquals(2, user.getGroups().size());
-        assertTrue(user.getGroups().contains(group1));
-        assertTrue(user.getGroups().contains(group2));
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testMissingIdentifier() {
         new User.Builder()
                 .identity("user1")
-                .addGroup("group1")
-                .addGroup("group2")
                 .build();
     }
 
@@ -63,29 +49,10 @@ public class TestUser {
     public void testMissingIdentity() {
         new User.Builder()
                 .identifier("1")
-                .addGroup("group1")
-                .addGroup("group2")
                 .build();
     }
 
     @Test
-    public void testMissingGroups() {
-        final String identifier = "1";
-        final String identity = "user1";
-
-        final User user = new User.Builder()
-                .identifier(identifier)
-                .identity(identity)
-                .build();
-
-        assertEquals(identifier, user.getIdentifier());
-        assertEquals(identity, user.getIdentity());
-
-        assertNotNull(user.getGroups());
-        assertEquals(0, user.getGroups().size());
-    }
-
-    @Test
     public void testFromUser() {
         final String identifier = "1";
         final String identity = "user1";
@@ -95,22 +62,14 @@ public class TestUser {
         final User user = new User.Builder()
                 .identifier(identifier)
                 .identity(identity)
-                .addGroup(group1)
-                .addGroup(group2)
                 .build();
 
         assertEquals(identifier, user.getIdentifier());
         assertEquals(identity, user.getIdentity());
 
-        assertNotNull(user.getGroups());
-        assertEquals(2, user.getGroups().size());
-        assertTrue(user.getGroups().contains(group1));
-        assertTrue(user.getGroups().contains(group2));
-
         final User user2 = new User.Builder(user).build();
         assertEquals(user.getIdentifier(), user2.getIdentifier());
         assertEquals(user.getIdentity(), user2.getIdentity());
-        assertEquals(user.getGroups(), user2.getGroups());
     }
 
     @Test(expected = IllegalStateException.class)
@@ -118,53 +77,9 @@ public class TestUser {
         final User user = new User.Builder()
                 .identifier("1")
                 .identity("user1")
-                .addGroup("group1")
-                .addGroup("group2")
                 .build();
 
         new User.Builder(user).identifier("2").build();
     }
 
-    @Test
-    public void testAddRemoveClearGroups() {
-        final User.Builder builder = new User.Builder()
-                .identifier("1")
-                .identity("user1")
-                .addGroup("group1");
-
-        final User user1 = builder.build();
-        assertNotNull(user1.getGroups());
-        assertEquals(1, user1.getGroups().size());
-        assertTrue(user1.getGroups().contains("group1"));
-
-        final Set<String> moreGroups = new HashSet<>();
-        moreGroups.add("group2");
-        moreGroups.add("group3");
-        moreGroups.add("group4");
-
-        final User user2 = builder.addGroups(moreGroups).build();
-        assertEquals(4, user2.getGroups().size());
-        assertTrue(user2.getGroups().contains("group1"));
-        assertTrue(user2.getGroups().contains("group2"));
-        assertTrue(user2.getGroups().contains("group3"));
-        assertTrue(user2.getGroups().contains("group4"));
-
-        final User user3 = builder.removeGroup("group2").build();
-        assertEquals(3, user3.getGroups().size());
-        assertTrue(user3.getGroups().contains("group1"));
-        assertTrue(user3.getGroups().contains("group3"));
-        assertTrue(user3.getGroups().contains("group4"));
-
-        final Set<String> removeGroups = new HashSet<>();
-        removeGroups.add("group1");
-        removeGroups.add("group4");
-
-        final User user4 = builder.removeGroups(removeGroups).build();
-        assertEquals(1, user4.getGroups().size());
-        assertTrue(user4.getGroups().contains("group3"));
-
-        final User user5 = builder.clearGroups().build();
-        assertEquals(0, user5.getGroups().size());
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
index e00af72..bfcfb7d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
@@ -369,7 +369,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho
                 }
 
                 @Override
-                public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
+                public AccessPolicy doAddAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
                     try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
                         return policyBasedAuthorizer.addAccessPolicy(accessPolicy);
                     }
@@ -418,7 +418,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, Autho
                 }
 
                 @Override
-                public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+                public void doOnConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
                     try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
                         policyBasedAuthorizer.onConfigured(configurationContext);
                     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/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 62ab2d3..13adedc 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
@@ -45,6 +45,7 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
 
     private final Set<Group> allGroups;
     private final Map<String,Group> groupsById;
+    private final Map<String, Set<Group>> groupsByUserIdentity;
 
     /**
      * Creates a new holder and populates all convenience data structures.
@@ -75,6 +76,9 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
         // create a convenience map to retrieve a group by id
         final Map<String, Group> groupByIdMap = Collections.unmodifiableMap(createGroupByIdMap(allGroups));
 
+        // create a convenience map to retrieve the groups for a user identity
+        final Map<String, Set<Group>> groupsByUserIdentityMap = Collections.unmodifiableMap(createGroupsByUserIdentityMap(allGroups, allUsers));
+
         // create a convenience map from resource id to policies
         final Map<String, Set<AccessPolicy>> policiesByResourceMap = Collections.unmodifiableMap(createResourcePolicyMap(allPolicies));
 
@@ -88,6 +92,7 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
         this.usersById = userByIdMap;
         this.usersByIdentity = userByIdentityMap;
         this.groupsById = groupByIdMap;
+        this.groupsByUserIdentity = groupsByUserIdentityMap;
         this.policiesByResource = policiesByResourceMap;
         this.policiesById = policiesByIdMap;
     }
@@ -158,12 +163,6 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
                     .identity(user.getIdentity())
                     .identifier(user.getIdentifier());
 
-            if (user.getGroup() != null) {
-                for (org.apache.nifi.authorization.file.generated.User.Group group : user.getGroup()) {
-                    builder.addGroup(group.getIdentifier());
-                }
-            }
-
             allUsers.add(builder.build());
         }
 
@@ -188,9 +187,9 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
                     .identifier(group.getIdentifier())
                     .name(group.getName());
 
-            // need to figured out what users are in this group by going through the users list
-            final Set<String> groupUsers = getUsersForGroup(users, group.getIdentifier());
-            builder.addUsers(groupUsers);
+            for (org.apache.nifi.authorization.file.generated.Group.User groupUser : group.getUser()) {
+                builder.addUser(groupUser.getIdentifier());
+            }
 
             allGroups.add(builder.build());
         }
@@ -199,32 +198,6 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
     }
 
     /**
-     * Gets the set of user identifiers that are part of the given group.
-     *
-     * @param users the JAXB Users element
-     * @param groupId the group id to get the users for
-     * @return the user identifiers that belong to the group with the given identifier
-     */
-    private Set<String> getUsersForGroup(org.apache.nifi.authorization.file.generated.Users users, final String groupId) {
-        Set<String> groupUsers = new HashSet<>();
-
-        if (users != null && users.getUser()!= null) {
-            for (org.apache.nifi.authorization.file.generated.User user : users.getUser()) {
-                if (user.getGroup() != null) {
-                    for (org.apache.nifi.authorization.file.generated.User.Group group : user.getGroup()) {
-                        if (group.getIdentifier().equals(groupId)) {
-                            groupUsers.add(user.getIdentifier());
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        return groupUsers;
-    }
-
-    /**
      * Creates a map from resource identifier to the set of policies for the given resource.
      *
      * @param allPolicies the set of all policies
@@ -288,6 +261,32 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
     }
 
     /**
+     * Creates a Map from user identity to the set of Groups for that identity.
+     *
+     * @param groups all groups
+     * @param users all users
+     * @return a Map from User identity to the set of Groups for that identity
+     */
+    private Map<String, Set<Group>> createGroupsByUserIdentityMap(final Set<Group> groups, final Set<User> users) {
+        Map<String, Set<Group>> groupsByUserIdentity = new HashMap<>();
+
+        for (User user : users) {
+            Set<Group> userGroups = new HashSet<>();
+            for (Group group : groups) {
+                for (String groupUser : group.getUsers()) {
+                    if (groupUser.equals(user.getIdentifier())) {
+                        userGroups.add(group);
+                    }
+                }
+            }
+
+            groupsByUserIdentity.put(user.getIdentity(), userGroups);
+        }
+
+        return groupsByUserIdentity;
+    }
+
+    /**
      * Creates a Map from policy identifier to AccessPolicy.
      *
      * @param policies the set of all access policies
@@ -353,4 +352,12 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
         return usersByIdentity.get(identity);
     }
 
+    @Override
+    public Set<Group> getGroups(String userIdentity) {
+        if (userIdentity == null) {
+            throw new IllegalArgumentException("User Identity cannot be null");
+        }
+        return groupsByUserIdentity.get(userIdentity);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/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 e49e24e..c11dc40 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
@@ -130,7 +130,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
     }
 
     @Override
-    public void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+    public void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
         try {
             final PropertyValue authorizationsPath = configurationContext.getProperty(PROP_AUTHORIZATIONS_FILE);
             if (StringUtils.isBlank(authorizationsPath.getValue())) {
@@ -324,13 +324,16 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
 
         // grant the user read access to the root process group resource
         if (rootGroupId != null) {
+            addAccessPolicy(authorizations, ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, adminUser.getIdentifier(), READ_CODE);
             addAccessPolicy(authorizations, ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, adminUser.getIdentifier(), WRITE_CODE);
         }
 
         // grant the user read/write access to the /tenants resource
+        addAccessPolicy(authorizations, ResourceType.Tenant.getValue(), adminUser.getIdentifier(), READ_CODE);
         addAccessPolicy(authorizations, ResourceType.Tenant.getValue(), adminUser.getIdentifier(), WRITE_CODE);
 
         // grant the user read/write access to the /policies resource
+        addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), READ_CODE);
         addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), WRITE_CODE);
     }
 
@@ -372,8 +375,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         // create mapping from Role to access policies
         final Map<Role,Set<RoleAccessPolicy>> roleAccessPolicies = RoleAccessPolicy.getMappings(rootGroupId);
 
-        final List<Policy> readPolicies = new ArrayList<>();
-        final List<Policy> readWritePolicies = new ArrayList<>();
+        final List<Policy> allPolicies = new ArrayList<>();
 
         for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
             // create the identifier of the new user based on the DN
@@ -389,9 +391,9 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
             // 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());
             if (group != null) {
-                org.apache.nifi.authorization.file.generated.User.Group userGroup = new org.apache.nifi.authorization.file.generated.User.Group();
-                userGroup.setIdentifier(group.getIdentifier());
-                user.getGroup().add(userGroup);
+                org.apache.nifi.authorization.file.generated.Group.User groupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+                groupUser.setIdentifier(userIdentifier);
+                group.getUser().add(groupUser);
             }
 
             // create policies based on the given role
@@ -400,16 +402,13 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
                 Set<RoleAccessPolicy> policies = roleAccessPolicies.get(role);
 
                 for (RoleAccessPolicy roleAccessPolicy : policies) {
-                    // determine if we should use the read policies or read-write policies
-                    List<Policy> searchPolicies = roleAccessPolicy.getActions().equals(RoleAccessPolicy.READ_ACTION)
-                            ? readPolicies : readWritePolicies;
 
                     // get the matching policy, or create a new one
                     Policy policy = getOrCreatePolicy(
-                            searchPolicies,
+                            allPolicies,
                             seedIdentity,
                             roleAccessPolicy.getResource(),
-                            roleAccessPolicy.getActions());
+                            roleAccessPolicy.getAction());
 
                     // determine if the user already exists in the policy
                     boolean userExists = false;
@@ -431,77 +430,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
 
         }
 
-        // merge the policies and add the result to the overall authorizations instance
-        final List<Policy> mergedPolicies = merge(readPolicies, readWritePolicies);
-        authorizations.getPolicies().getPolicy().addAll(mergedPolicies);
-    }
-
-    /**
-     * Merges the provided read and read-write policies. Any users that are in a read policy and also in a read-write
-     * policy for the same resource will be removed from the read policy. If users are still left in the read policy
-     * after checking each user, then the read policy will still be included in the merged list.
-     *
-     * @param readPolicies the read policies
-     * @param readWritePolicies the read-write policies
-     * @return the merged list of policies
-     */
-    private List<Policy> merge(List<Policy> readPolicies, List<Policy> readWritePolicies) {
-        final List<Policy> mergedPolicies = new ArrayList<>(readWritePolicies);
-
-        logger.debug("Merging {} read policies and {} read-write policies",
-                new Object[] {readPolicies.size(), readWritePolicies.size()});
-
-        for (Policy readPolicy : readPolicies) {
-            logger.debug("Processing read policy {} for resource {} with actions {}",
-                    new Object[] {readPolicy.getIdentifier(), readPolicy.getResource(), readPolicy.getAction()});
-
-            // try to find a matching read-write policy for the same resource
-            Policy foundReadWritePolicy = null;
-            for (Policy readWritePolicy : readWritePolicies) {
-                if (readWritePolicy.getResource().equals(readPolicy.getResource())) {
-                    foundReadWritePolicy = readWritePolicy;
-                    break;
-                }
-            }
-
-            // if we didn't find a match then we just add the current read policy to the merged list
-            if (foundReadWritePolicy == null) {
-                logger.debug("no matching write policy found, adding read policy {} to merged policies",
-                        new Object[] {readPolicy.getIdentifier()});
-                mergedPolicies.add(readPolicy);
-            } else {
-                // check each user from the read policy
-                Iterator<Policy.User> userIter = readPolicy.getUser().iterator();
-                while (userIter.hasNext()) {
-                    Policy.User readUser = userIter.next();
-
-                    // determine if the user from the read policy exists in the read-write policy
-                    boolean userInReadWrite = false;
-                    for (Policy.User readWriteUser : foundReadWritePolicy.getUser()) {
-                        if (readWriteUser.getIdentifier().equals(readUser.getIdentifier())) {
-                            userInReadWrite = true;
-                            break;
-                        }
-                    }
-
-                    // if the user was in the read-write policy, remove them from read policy
-                    if (userInReadWrite) {
-                        logger.debug("Removing user {} from read policy {}", new Object[] {readUser.getIdentifier(), readPolicy.getIdentifier()});
-                        userIter.remove();
-                    }
-                }
-
-                // after checking all users, see if any are still left in the read policy
-                // if there are still some users, then add the read policy to the merged list
-                if (readPolicy.getUser().size() > 0) {
-                    logger.debug("Read policy still has {} users, adding read policy {} to merged list",
-                            new Object[] {readPolicy.getUser().size(), readPolicy.getIdentifier()});
-                    mergedPolicies.add(readPolicy);
-                }
-            }
-        }
-
-        return mergedPolicies;
+        authorizations.getPolicies().getPolicy().addAll(allPolicies);
     }
 
     /**
@@ -652,16 +581,11 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         jaxbGroup.setIdentifier(group.getIdentifier());
         jaxbGroup.setName(group.getName());
 
-        // find each user and add the group to that user
+        // add each user to the group
         for (String groupUser : group.getUsers()) {
-            for (org.apache.nifi.authorization.file.generated.User jaxbUser : jaxbUsers) {
-                if (jaxbUser.getIdentifier().equals(groupUser)) {
-                    final org.apache.nifi.authorization.file.generated.User.Group jaxbUserGroup = new org.apache.nifi.authorization.file.generated.User.Group();
-                    jaxbUserGroup.setIdentifier(group.getIdentifier());
-                    jaxbUser.getGroup().add(jaxbUserGroup);
-                    break;
-                }
-            }
+            org.apache.nifi.authorization.file.generated.Group.User jaxbGroupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+            jaxbGroupUser.setIdentifier(groupUser);
+            jaxbGroup.getUser().add(jaxbGroupUser);
         }
 
         authorizations.getGroups().getGroup().add(jaxbGroup);
@@ -687,9 +611,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
 
         final Authorizations authorizations = this.authorizationsHolder.get().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());
-
         // 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()) {
@@ -704,41 +625,12 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
             return null;
         }
 
-        // now we know group and all users exist so perform the updates
-
-        // first find each user and add the group to that user
+        // reset the list of users and add each user to the group
+        updateGroup.getUser().clear();
         for (String groupUser : group.getUsers()) {
-            for (org.apache.nifi.authorization.file.generated.User jaxbUser : jaxbUsers) {
-                if (jaxbUser.getIdentifier().equals(groupUser)) {
-                    final org.apache.nifi.authorization.file.generated.User.Group jaxbUserGroup = new org.apache.nifi.authorization.file.generated.User.Group();
-                    jaxbUserGroup.setIdentifier(group.getIdentifier());
-                    jaxbUser.getGroup().add(jaxbUserGroup);
-                    break;
-                }
-            }
-        }
-
-        // now go through every user, check each group in the user to see if it still
-        for (org.apache.nifi.authorization.file.generated.User jaxbUser : authorizations.getUsers().getUser()) {
-            Iterator<org.apache.nifi.authorization.file.generated.User.Group> userGroupIter = jaxbUser.getGroup().iterator();
-            while (userGroupIter.hasNext()) {
-                final org.apache.nifi.authorization.file.generated.User.Group userGroup = userGroupIter.next();
-
-                // we only care about finding the group that is currently being updated
-                if (userGroup.getIdentifier().equals(group.getIdentifier())) {
-                    boolean stillInGroup = false;
-                    for (String groupUser : group.getUsers()) {
-                        if (groupUser.equals(jaxbUser.getIdentifier())) {
-                            stillInGroup = true;
-                            break;
-                        }
-                    }
-
-                    if (!stillInGroup) {
-                        userGroupIter.remove();
-                    }
-                }
-            }
+            org.apache.nifi.authorization.file.generated.Group.User jaxbGroupUser = new org.apache.nifi.authorization.file.generated.Group.User();
+            jaxbGroupUser.setIdentifier(groupUser);
+            updateGroup.getUser().add(jaxbGroupUser);
         }
 
         updateGroup.setName(group.getName());
@@ -753,18 +645,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         final Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
         final List<org.apache.nifi.authorization.file.generated.Group> groups = authorizations.getGroups().getGroup();
 
-        // for each user iterate over the group references and remove the group reference if it matches the group being deleted
-        for (org.apache.nifi.authorization.file.generated.User user : authorizations.getUsers().getUser()) {
-            Iterator<org.apache.nifi.authorization.file.generated.User.Group> userGroupIter = user.getGroup().iterator();
-            while (userGroupIter.hasNext()) {
-                org.apache.nifi.authorization.file.generated.User.Group userGroup = userGroupIter.next();
-                if (userGroup.getIdentifier().equals(group.getIdentifier())) {
-                    userGroupIter.remove();
-                    break;
-                }
-            }
-        }
-
         // 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()) {
             Iterator<Policy.Group> policyGroupIter = policy.getGroup().iterator();
@@ -844,12 +724,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         final org.apache.nifi.authorization.file.generated.User jaxbUser = new org.apache.nifi.authorization.file.generated.User();
         jaxbUser.setIdentifier(user.getIdentifier());
         jaxbUser.setIdentity(user.getIdentity());
-
-        for (String groupIdentifier : user.getGroups()) {
-            org.apache.nifi.authorization.file.generated.User.Group group = new org.apache.nifi.authorization.file.generated.User.Group();
-            group.setIdentifier(groupIdentifier);
-            jaxbUser.getGroup().add(group);
-        }
         return jaxbUser;
     }
 
@@ -896,14 +770,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
             return null;
         } else {
             updateUser.setIdentity(user.getIdentity());
-
-            updateUser.getGroup().clear();
-            for (String groupIdentifier : user.getGroups()) {
-                org.apache.nifi.authorization.file.generated.User.Group group = new org.apache.nifi.authorization.file.generated.User.Group();
-                group.setIdentifier(groupIdentifier);
-                updateUser.getGroup().add(group);
-            }
-
             saveAndRefreshHolder(authorizations);
 
             final AuthorizationsHolder holder = authorizationsHolder.get();
@@ -920,6 +786,18 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         final Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
         final List<org.apache.nifi.authorization.file.generated.User> users = authorizations.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();
+            while (groupUserIter.hasNext()) {
+                org.apache.nifi.authorization.file.generated.Group.User groupUser = groupUserIter.next();
+                if (groupUser.getIdentifier().equals(user.getIdentifier())) {
+                    groupUserIter.remove();
+                    break;
+                }
+            }
+        }
+
         // remove any references to the user being deleted from policies
         for (Policy policy : authorizations.getPolicies().getPolicy()) {
             Iterator<Policy.User> policyUserIter = policy.getUser().iterator();
@@ -960,7 +838,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
     // ------------------ AccessPolicies ------------------
 
     @Override
-    public synchronized AccessPolicy addAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
+    public synchronized AccessPolicy doAddAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
         if (accessPolicy == null) {
             throw new IllegalArgumentException("AccessPolicy cannot be null");
         }
@@ -981,7 +859,20 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
     private Policy createJAXBPolicy(final AccessPolicy accessPolicy) {
         final Policy policy = new Policy();
         policy.setIdentifier(accessPolicy.getIdentifier());
-        transferState(accessPolicy, policy);
+        policy.setResource(accessPolicy.getResource());
+
+        switch (accessPolicy.getAction()) {
+            case READ:
+                policy.setAction(READ_CODE);
+                break;
+            case WRITE:
+                policy.setAction(WRITE_CODE);
+                break;
+            default:
+                break;
+        }
+
+        transferUsersAndGroups(accessPolicy, policy);
         return policy;
     }
 
@@ -1018,7 +909,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         }
 
         // update the Policy, save, reload, and return
-        transferState(accessPolicy, updatePolicy);
+        transferUsersAndGroups(accessPolicy, updatePolicy);
         saveAndRefreshHolder(authorizations);
 
         final AuthorizationsHolder holder = authorizationsHolder.get();
@@ -1073,9 +964,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
      * @param accessPolicy the AccessPolicy to transfer state from
      * @param policy the Policy to transfer state to
      */
-    private void transferState(AccessPolicy accessPolicy, Policy policy) {
-        policy.setResource(accessPolicy.getResource());
-
+    private void transferUsersAndGroups(AccessPolicy accessPolicy, Policy policy) {
         // add users to the policy
         policy.getUser().clear();
         for (String userIdentifier : accessPolicy.getUsers()) {
@@ -1091,13 +980,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
             policyGroup.setIdentifier(groupIdentifier);
             policy.getGroup().add(policyGroup);
         }
-
-        // add the action to the access policy
-        if (accessPolicy.getAction() == RequestAction.READ) {
-            policy.setAction(READ_CODE);
-        } else {
-            policy.setAction(WRITE_CODE);
-        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/RoleAccessPolicy.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/RoleAccessPolicy.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/RoleAccessPolicy.java
index 24857f1..c8a0f53 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/RoleAccessPolicy.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/RoleAccessPolicy.java
@@ -33,19 +33,19 @@ public final class RoleAccessPolicy {
     static final String WRITE_ACTION = "W";
 
     private final String resource;
-    private final String actions;
+    private final String action;
 
-    private RoleAccessPolicy(final String resource, final String actions) {
+    private RoleAccessPolicy(final String resource, final String action) {
         this.resource = resource;
-        this.actions = actions;
+        this.action = action;
     }
 
     public String getResource() {
         return resource;
     }
 
-    public String getActions() {
-        return actions;
+    public String getAction() {
+        return action;
     }
 
     public static Map<Role,Set<RoleAccessPolicy>> getMappings(final String rootGroupId) {
@@ -62,13 +62,18 @@ public final class RoleAccessPolicy {
 
         final Set<RoleAccessPolicy> provenancePolicies = new HashSet<>();
         provenancePolicies.add(new RoleAccessPolicy(ResourceType.Provenance.getValue(), READ_ACTION));
+        if (rootGroupId != null) {
+            provenancePolicies.add(new RoleAccessPolicy(ResourceType.ProvenanceEvent.getValue() + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
+        }
         roleAccessPolicies.put(Role.ROLE_PROVENANCE, Collections.unmodifiableSet(provenancePolicies));
 
         final Set<RoleAccessPolicy> dfmPolicies = new HashSet<>();
         dfmPolicies.add(new RoleAccessPolicy(ResourceType.Flow.getValue(), READ_ACTION));
+        dfmPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
         dfmPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), WRITE_ACTION));
         dfmPolicies.add(new RoleAccessPolicy(ResourceType.System.getValue(), READ_ACTION));
         if (rootGroupId != null) {
+            dfmPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
             dfmPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, WRITE_ACTION));
         }
         roleAccessPolicies.put(Role.ROLE_DFM, Collections.unmodifiableSet(dfmPolicies));
@@ -79,16 +84,20 @@ public final class RoleAccessPolicy {
         if (rootGroupId != null) {
             adminPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
         }
+        adminPolicies.add(new RoleAccessPolicy(ResourceType.Tenant.getValue(), READ_ACTION));
         adminPolicies.add(new RoleAccessPolicy(ResourceType.Tenant.getValue(), WRITE_ACTION));
+        adminPolicies.add(new RoleAccessPolicy(ResourceType.Policy.getValue(), READ_ACTION));
         adminPolicies.add(new RoleAccessPolicy(ResourceType.Policy.getValue(), WRITE_ACTION));
         roleAccessPolicies.put(Role.ROLE_ADMIN, Collections.unmodifiableSet(adminPolicies));
 
         final Set<RoleAccessPolicy> proxyPolicies = new HashSet<>();
+        proxyPolicies.add(new RoleAccessPolicy(ResourceType.Proxy.getValue(), READ_ACTION));
         proxyPolicies.add(new RoleAccessPolicy(ResourceType.Proxy.getValue(), WRITE_ACTION));
         roleAccessPolicies.put(Role.ROLE_PROXY, Collections.unmodifiableSet(proxyPolicies));
 
         final Set<RoleAccessPolicy> nifiPolicies = new HashSet<>();
         nifiPolicies.add(new RoleAccessPolicy(ResourceType.Controller.getValue(), READ_ACTION));
+        nifiPolicies.add(new RoleAccessPolicy(ResourceType.SiteToSite.getValue(), READ_ACTION));
         nifiPolicies.add(new RoleAccessPolicy(ResourceType.SiteToSite.getValue(), WRITE_ACTION));
         roleAccessPolicies.put(Role.ROLE_NIFI, Collections.unmodifiableSet(nifiPolicies));
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/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 9b24c7a..452af96 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
@@ -17,6 +17,20 @@
 
     <!-- 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">
@@ -44,20 +58,6 @@
 
     <!-- user -->
     <xs:complexType name="User">
-        <xs:sequence>
-            <xs:element name="group" 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">

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
index fc08e71..efe078f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
@@ -24,6 +24,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.util.file.FileUtils;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -79,14 +80,15 @@ public class FileAuthorizerTest {
             "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
             "<authorizations>" +
             "  <groups>" +
-            "    <group identifier=\"group-1\" name=\"group-1\" />" +
-            "    <group identifier=\"group-2\" name=\"group-2\" />" +
+            "    <group identifier=\"group-1\" name=\"group-1\">" +
+            "       <user identifier=\"user-1\" />" +
+            "    </group>" +
+            "    <group identifier=\"group-2\" name=\"group-2\">" +
+            "       <user identifier=\"user-2\" />" +
+            "    </group>" +
             "  </groups>" +
             "  <users>" +
-            "    <user identifier=\"user-1\" identity=\"user-1\">" +
-            "      <group identifier=\"group-1\" />" +
-            "      <group identifier=\"group-2\" />" +
-            "    </user>\n" +
+            "    <user identifier=\"user-1\" identity=\"user-1\" />" +
             "    <user identifier=\"user-2\" identity=\"user-2\" />" +
             "  </users>" +
             "  <policies>" +
@@ -154,13 +156,11 @@ public class FileAuthorizerTest {
         final Set<User> users = authorizer.getUsers();
         assertEquals(1, users.size());
 
-        // the user has monitor and DFM, but we should only end up with one policy per resource
-        // since DFM has RW to all the same resources that monitor has R
         UsersAndAccessPolicies usersAndAccessPolicies = authorizer.getUsersAndAccessPolicies();
         assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.Flow.getValue()).size());
-        assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.Controller.getValue()).size());
+        assertEquals(2, usersAndAccessPolicies.getAccessPolicies(ResourceType.Controller.getValue()).size());
         assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.System.getValue()).size());
-        assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
+        assertEquals(2, usersAndAccessPolicies.getAccessPolicies(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
     }
 
     @Test
@@ -216,7 +216,7 @@ public class FileAuthorizerTest {
 
         // verify user2's policies
         final Map<String,Set<RequestAction>> user2Policies = getResourceActions(policies, user2);
-        assertEquals(1, user2Policies.size());
+        assertEquals(2, user2Policies.size());
 
         assertTrue(user2Policies.containsKey(ResourceType.Provenance.getValue()));
         assertEquals(1, user2Policies.get(ResourceType.Provenance.getValue()).size());
@@ -231,7 +231,7 @@ public class FileAuthorizerTest {
         assertTrue(user3Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
 
         assertTrue(user3Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(1, user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
+        assertEquals(2, user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
         assertTrue(user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.WRITE));
 
         // verify user4's policies
@@ -247,11 +247,11 @@ public class FileAuthorizerTest {
         assertTrue(user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
 
         assertTrue(user4Policies.containsKey(ResourceType.Tenant.getValue()));
-        assertEquals(1, user4Policies.get(ResourceType.Tenant.getValue()).size());
+        assertEquals(2, user4Policies.get(ResourceType.Tenant.getValue()).size());
         assertTrue(user4Policies.get(ResourceType.Tenant.getValue()).contains(RequestAction.WRITE));
 
         assertTrue(user4Policies.containsKey(ResourceType.Policy.getValue()));
-        assertEquals(1, user4Policies.get(ResourceType.Policy.getValue()).size());
+        assertEquals(2, user4Policies.get(ResourceType.Policy.getValue()).size());
         assertTrue(user4Policies.get(ResourceType.Policy.getValue()).contains(RequestAction.WRITE));
 
         // verify user5's policies
@@ -259,7 +259,7 @@ public class FileAuthorizerTest {
         assertEquals(1, user5Policies.size());
 
         assertTrue(user5Policies.containsKey(ResourceType.Proxy.getValue()));
-        assertEquals(1, user5Policies.get(ResourceType.Proxy.getValue()).size());
+        assertEquals(2, user5Policies.get(ResourceType.Proxy.getValue()).size());
         assertTrue(user5Policies.get(ResourceType.Proxy.getValue()).contains(RequestAction.WRITE));
 
         // verify user6's policies
@@ -267,7 +267,7 @@ public class FileAuthorizerTest {
         assertEquals(2, user6Policies.size());
 
         assertTrue(user6Policies.containsKey(ResourceType.SiteToSite.getValue()));
-        assertEquals(1, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
+        assertEquals(2, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
         assertTrue(user6Policies.get(ResourceType.SiteToSite.getValue()).contains(RequestAction.WRITE));
     }
 
@@ -529,7 +529,7 @@ public class FileAuthorizerTest {
                     && group.getUsers().size() == 1 && group.getUsers().contains("user-1")) {
                 foundGroup1 = true;
             } else if (group.getIdentifier().equals("group-2") && group.getName().equals("group-2")
-                    && group.getUsers().size() == 1 && group.getUsers().contains("user-1")) {
+                    && group.getUsers().size() == 1 && group.getUsers().contains("user-2")) {
                 foundGroup2 = true;
             }
         }
@@ -544,12 +544,9 @@ public class FileAuthorizerTest {
         boolean foundUser2 = false;
 
         for (User user : users) {
-            if (user.getIdentifier().equals("user-1") && user.getIdentity().equals("user-1")
-                    && user.getGroups().size() == 2 && user.getGroups().contains("group-1")
-                    && user.getGroups().contains("group-2")) {
+            if (user.getIdentifier().equals("user-1") && user.getIdentity().equals("user-1")) {
                 foundUser1 = true;
-            } else if (user.getIdentifier().equals("user-2") && user.getIdentity().equals("user-2")
-                    && user.getGroups().size() == 0) {
+            } else if (user.getIdentifier().equals("user-2") && user.getIdentity().equals("user-2")) {
                 foundUser2 = true;
             }
         }
@@ -598,17 +595,12 @@ public class FileAuthorizerTest {
         final User user = new User.Builder()
                 .identifier("user-1")
                 .identity("user-identity-1")
-                .addGroup("group1")
-                .addGroup("group2")
                 .build();
 
         final User addedUser = authorizer.addUser(user);
         assertNotNull(addedUser);
         assertEquals(user.getIdentifier(), addedUser.getIdentifier());
         assertEquals(user.getIdentity(), addedUser.getIdentity());
-        assertEquals(2, addedUser.getGroups().size());
-        assertTrue(addedUser.getGroups().contains("group1"));
-        assertTrue(addedUser.getGroups().contains("group2"));
 
         final Set<User> users = authorizer.getUsers();
         assertEquals(1, users.size());
@@ -711,15 +703,12 @@ public class FileAuthorizerTest {
         final User user = new User.Builder()
                 .identifier("user-1")
                 .identity("new-identity")
-                .addGroup("new-group")
                 .build();
 
         final User updatedUser = authorizer.updateUser(user);
         assertNotNull(updatedUser);
         assertEquals(user.getIdentifier(), updatedUser.getIdentifier());
         assertEquals(user.getIdentity(), updatedUser.getIdentity());
-        assertEquals(1, updatedUser.getGroups().size());
-        assertTrue(updatedUser.getGroups().contains("new-group"));
     }
 
     @Test
@@ -731,7 +720,6 @@ public class FileAuthorizerTest {
         final User user = new User.Builder()
                 .identifier("user-X")
                 .identity("new-identity")
-                .addGroup("new-group")
                 .build();
 
         final User updatedUser = authorizer.updateUser(user);
@@ -781,10 +769,6 @@ public class FileAuthorizerTest {
 
         final Set<Group> groups = authorizer.getGroups();
         assertEquals(3, groups.size());
-
-        final User user = authorizer.getUser("user-1");
-        assertNotNull(user);
-        assertTrue(user.getGroups().contains(group.getIdentifier()));
     }
 
 
@@ -832,12 +816,6 @@ public class FileAuthorizerTest {
         authorizer.onConfigured(configurationContext);
         assertEquals(2, authorizer.getGroups().size());
 
-        // retrieve user-1 and verify its in group-1
-        final User user1 = authorizer.getUser("user-1");
-        assertNotNull(user1);
-        assertEquals(2, user1.getGroups().size());
-        assertTrue(user1.getGroups().contains("group-1"));
-
         final AccessPolicy policy1 = authorizer.getAccessPolicy("policy-1");
         assertTrue(policy1.getGroups().contains("group-1"));
 
@@ -856,12 +834,6 @@ public class FileAuthorizerTest {
         // verify we can no longer retrieve group-1 by identifier
         assertNull(authorizer.getGroup(group.getIdentifier()));
 
-        // verify user-1 is no longer in group-1
-        final User updatedUser1 = authorizer.getUser("user-1");
-        assertNotNull(updatedUser1);
-        assertEquals(1, updatedUser1.getGroups().size());
-        assertFalse(updatedUser1.getGroups().contains("group-1"));
-
         // verify group-1 is no longer in policy-1
         final AccessPolicy updatedPolicy1 = authorizer.getAccessPolicy("policy-1");
         assertFalse(updatedPolicy1.getGroups().contains("group-1"));
@@ -890,12 +862,9 @@ public class FileAuthorizerTest {
         assertEquals(2, authorizer.getGroups().size());
 
         // verify user-1 is in group-1 before the update
-        final User user1Before = authorizer.getUser("user-1");
-        assertTrue(user1Before.getGroups().contains("group-1"));
-
-        // verify user-2 is NOT in group-1 before the update
-        final User user2Before = authorizer.getUser("user-2");
-        assertFalse(user2Before.getGroups().contains("group-1"));
+        final Group groupBefore = authorizer.getGroup("group-1");
+        assertEquals(1, groupBefore.getUsers().size());
+        assertTrue(groupBefore.getUsers().contains("user-1"));
 
         final Group group = new Group.Builder()
                 .identifier("group-1")
@@ -907,13 +876,8 @@ public class FileAuthorizerTest {
         assertEquals(group.getIdentifier(), updatedGroup.getIdentifier());
         assertEquals(group.getName(), updatedGroup.getName());
 
-        // user-1 should no longer be in group-1
-        final User user1After = authorizer.getUser("user-1");
-        assertFalse(user1After.getGroups().contains("group-1"));
-
-        // user-2 should now be in group-1
-        final User user2After = authorizer.getUser("user-2");
-        assertTrue(user2After.getGroups().contains("group-1"));
+        assertEquals(1, updatedGroup.getUsers().size());
+        assertTrue(updatedGroup.getUsers().contains("user-2"));
     }
 
     @Test
@@ -967,9 +931,13 @@ public class FileAuthorizerTest {
                 .action(RequestAction.READ)
                 .build();
 
-        final AccessPolicy returnedPolicy2 = authorizer.addAccessPolicy(policy2);
-        assertNotNull(returnedPolicy2);
-        assertEquals(2, authorizer.getAccessPolicies().size());
+        try {
+            final AccessPolicy returnedPolicy2 = authorizer.addAccessPolicy(policy2);
+            Assert.fail("Should have thrown exception");
+        } catch (Exception e) {
+        }
+
+        assertEquals(1, authorizer.getAccessPolicies().size());
     }
 
     @Test
@@ -1043,7 +1011,7 @@ public class FileAuthorizerTest {
         final AccessPolicy updateAccessPolicy = authorizer.updateAccessPolicy(policy);
         assertNotNull(updateAccessPolicy);
         assertEquals("policy-1", updateAccessPolicy.getIdentifier());
-        assertEquals("resource-A", updateAccessPolicy.getResource());
+        assertEquals("/flow", updateAccessPolicy.getResource());
 
         assertEquals(1, updateAccessPolicy.getUsers().size());
         assertTrue(updateAccessPolicy.getUsers().contains("user-A"));

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
index ea12ad5..03260f1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
@@ -71,12 +71,12 @@ public class TestFlowController {
         properties.setProperty("nifi.remote.input.socket.port", "");
         properties.setProperty("nifi.remote.input.secure", "");
 
-        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").build();
-        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").build();
-
-        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").addGroup(group1.getIdentifier()).build();
+        User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build();
         User user2 = new User.Builder().identifier("user-id-2").identity("user-2").build();
 
+        Group group1 = new Group.Builder().identifier("group-id-1").name("group-1").addUser(user1.getIdentifier()).build();
+        Group group2 = new Group.Builder().identifier("group-id-2").name("group-2").build();
+
         AccessPolicy policy1 = new AccessPolicy.Builder()
                 .identifier("policy-id-1")
                 .resource("resource1")
@@ -135,7 +135,7 @@ public class TestFlowController {
         // had a problem verifying the call to inheritFingerprint didn't happen, so just verify none of the add methods got called
         verify(authorizer, times(0)).addUser(any(User.class));
         verify(authorizer, times(0)).addGroup(any(Group.class));
-        verify(authorizer, times(0)).addAccessPolicy(any(AccessPolicy.class));
+        //verify(authorizer, times(0)).addAccessPolicy(any(AccessPolicy.class));
     }
 
     @Test(expected = UninheritableFlowException.class)

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index c77778d..3526f32 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -515,10 +515,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     @Override
     public UserEntity updateUser(final Revision revision, final UserDTO userDTO) {
         final Authorizable usersAuthorizable = authorizableLookup.getTenantAuthorizable();
+        final Set<Group> groups = userGroupDAO.getUserGroupsForUser(userDTO.getId());
         final RevisionUpdate<UserDTO> snapshot = updateComponent(revision,
                 usersAuthorizable,
                 () -> userDAO.updateUser(userDTO),
-                user -> dtoFactory.createUserDto(user, user.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet())));
+                user -> dtoFactory.createUserDto(user, groups.stream().map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet())));
 
         final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
         return entityFactory.createUserEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), accessPolicy);
@@ -934,7 +935,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     @Override
     public UserEntity deleteUser(final Revision revision, final String userId) {
         final User user = userDAO.getUser(userId);
-        final Set<TenantEntity> userGroups = user != null ? user.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()) : null;
+        final Set<TenantEntity> userGroups = user != null ? userGroupDAO.getUserGroupsForUser(userId).stream()
+                .map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()) : null;
         final UserDTO snapshot = deleteComponent(
                 revision,
                 authorizableLookup.getTenantAuthorizable(),
@@ -1229,8 +1231,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         final Authorizable tenantAuthorizable = authorizableLookup.getTenantAuthorizable();
         final String creator = NiFiUserUtils.getNiFiUserIdentity();
         final User newUser = userDAO.createUser(userDTO);
-        final UserDTO newUserDto = dtoFactory.createUserDto(newUser, newUser.getGroups().stream()
-                .map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()));
+        final Set<Group> groups = userGroupDAO.getUserGroupsForUser(newUser.getIdentifier());
+        final UserDTO newUserDto = dtoFactory.createUserDto(newUser, groups.stream()
+                .map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()));
 
         final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getTenantAuthorizable());
         return entityFactory.createUserEntity(newUserDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
@@ -2233,20 +2236,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
 
     @Override
     public UserEntity getUser(final String userId) {
-        final Authorizable usersAuthorizable = authorizableLookup.getTenantAuthorizable();
-        final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userId));
-        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
         final User user = userDAO.getUser(userId);
-        final Set<TenantEntity> userGroups = user.getGroups().stream()
-            .map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
-        return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups), userRevision, accessPolicy);
-    }
-
-    private UserEntity createUserEntity(final User user) {
-        final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(user.getIdentifier()));
-        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getTenantAuthorizable());
-        final Set<TenantEntity> userGroups = user.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
-        return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups), userRevision, accessPolicy);
+        return createUserEntity(user);
     }
 
     @Override
@@ -2257,6 +2248,14 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
             .collect(Collectors.toSet());
     }
 
+    private UserEntity createUserEntity(final User user) {
+        final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(user.getIdentifier()));
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getTenantAuthorizable());
+        final Set<TenantEntity> userGroups = userGroupDAO.getUserGroupsForUser(user.getIdentifier()).stream()
+                .map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
+        return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups), userRevision, accessPolicy);
+    }
+
     private UserGroupEntity createUserGroupEntity(final Group userGroup) {
         final RevisionDTO userGroupRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userGroup.getIdentifier()));
         final Set<TenantEntity> users = userGroup.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet());

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java
index 0e48584..b6c299d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java
@@ -46,6 +46,14 @@ public interface UserGroupDAO {
     Group getUserGroup(String userGroupId);
 
     /**
+     * Gets the groups for the user with the specified ID.
+     *
+     * @param userId The user ID
+     * @return The set of groups
+     */
+    Set<Group> getUserGroupsForUser(String userId);
+
+    /**
      * Gets all user groups.
      *
      * @return The user group transfer objects

http://git-wip-us.apache.org/repos/asf/nifi/blob/c5889314/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
index 4aae278..3f12f73 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java
@@ -107,7 +107,7 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
                 }
 
                 @Override
-                public AccessPolicy addAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
+                public AccessPolicy doAddAccessPolicy(final AccessPolicy accessPolicy) throws AuthorizationAccessException {
                     throw new IllegalStateException(MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER);
                 }
 
@@ -141,7 +141,7 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
                 }
 
                 @Override
-                public void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+                public void doOnConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
                 }
 
                 @Override
@@ -220,6 +220,13 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
     }
 
     @Override
+    public Set<Group> getUserGroupsForUser(String userId) {
+        return authorizer.getGroups().stream()
+                .filter(g -> g.getUsers().contains(userId))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
     public Set<Group> getUserGroups() {
         return authorizer.getGroups();
     }
@@ -278,11 +285,7 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
     }
 
     private User buildUser(final String identifier, final UserDTO userDTO) {
-        final Set<TenantEntity> groups = userDTO.getUserGroups();
         final User.Builder builder = new User.Builder().identifier(identifier).identity(userDTO.getIdentity());
-        if (groups != null) {
-            builder.addGroups(groups.stream().map(ComponentEntity::getId).collect(Collectors.toSet()));
-        }
         return builder.build();
     }