Repository: nifi
Updated Branches:
  refs/heads/master 9bb6dcb5e -> 714925358


NIFI-1884
- Defining API for Users, Groups, and Policies
- Updating hashCode and equals methods
- Documenting that returned sets are unmodifiable
- Adding builders and unit tests
- Refactoring update methods in MutableAuthorizer to not take a string id
- Refactoring builders to use constructors for seeding
- Fixing toString() methods and cleaning up constructors that don't need to 
worry about null sets
- Changing MutableAuthorizer to an abstract class and providing implementation 
of authorize
- This closes #452


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

Branch: refs/heads/master
Commit: 714925358e9b2394aabd1ef9a63ca80b8320f42f
Parents: 9bb6dcb
Author: Bryan Bende <[email protected]>
Authored: Mon May 16 17:11:41 2016 -0400
Committer: Matt Gilman <[email protected]>
Committed: Tue May 24 09:24:11 2016 -0400

----------------------------------------------------------------------
 .../AbstractPolicyBasedAuthorizer.java          | 220 ++++++++++++
 .../apache/nifi/authorization/AccessPolicy.java | 356 +++++++++++++++++++
 .../org/apache/nifi/authorization/Group.java    | 226 ++++++++++++
 .../org/apache/nifi/authorization/User.java     | 229 ++++++++++++
 .../TestAbstractPolicyBasedAuthorizer.java      | 165 +++++++++
 .../nifi/authorization/TestAccessPolicy.java    | 287 +++++++++++++++
 .../apache/nifi/authorization/TestGroup.java    | 169 +++++++++
 .../org/apache/nifi/authorization/TestUser.java | 170 +++++++++
 8 files changed, 1822 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/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
new file mode 100644
index 0000000..1200017
--- /dev/null
+++ 
b/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+
+import java.util.Set;
+
+/**
+ * An Authorizer that provides management of users, groups, and policies.
+ */
+public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
+
+    @Override
+    public final AuthorizationResult authorize(AuthorizationRequest request) 
throws AuthorizationAccessException {
+        final Set<AccessPolicy> policies = 
getAccessPolicies(request.getResource());
+
+        if (policies == null || policies.isEmpty()) {
+            return AuthorizationResult.resourceNotFound();
+        }
+
+        final User user = getUserByIdentity(request.getIdentity());
+
+        if (user == null) {
+            return AuthorizationResult.denied("Unknown user with identity " + 
request.getIdentity());
+        }
+
+        for (AccessPolicy policy : policies) {
+            final boolean containsAction = 
policy.getActions().contains(request.getAction());
+            final boolean containsUser = 
policy.getUsers().contains(user.getIdentifier());
+            if (containsAction && (containsUser || containsGroup(user, 
policy)) ) {
+                return AuthorizationResult.approved();
+            }
+        }
+
+        return AuthorizationResult.denied();
+    }
+
+
+    private boolean containsGroup(final User user, final AccessPolicy policy) {
+        if (user.getGroups().isEmpty() || policy.getGroups().isEmpty()) {
+            return false;
+        }
+
+        for (String userGroup : user.getGroups()) {
+            if (policy.getGroups().contains(userGroup)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Adds a new group.
+     *
+     * @param group the Group to add
+     * @return the added Group
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Group addGroup(Group group) throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves a Group by id.
+     *
+     * @param identifier the identifier of the Group to retrieve
+     * @return the Group with the given identifier, or null if no matching 
group was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Group getGroup(String identifier) throws 
AuthorizationAccessException;
+
+    /**
+     * The group represented by the provided instance will be updated based on 
the provided instance.
+     *
+     * @param group an updated group instance
+     * @return the updated group instance, or null if no matching group was 
found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Group updateGroup(Group group) throws 
AuthorizationAccessException;
+
+    /**
+     * Deletes the given group.
+     *
+     * @param group the group to delete
+     * @return the deleted group, or null if no matching group was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Group deleteGroup(Group group) throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves all groups.
+     *
+     * @return a list of groups
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Set<Group> getGroups() throws AuthorizationAccessException;
+
+
+    /**
+     * Adds the given user.
+     *
+     * @param user the user to add
+     * @return the user that was added
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract User addUser(User user) throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves the user with the given identifier.
+     *
+     * @param identifier the id of the user to retrieve
+     * @return the user with the given id, or null if no matching user was 
found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract User getUser(String identifier) throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves the user with the given identity.
+     *
+     * @param identity the identity of the user to retrieve
+     * @return the user with the given identity, or null if no matching user 
was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract User getUserByIdentity(String identity) throws 
AuthorizationAccessException;
+
+    /**
+     * The user represented by the provided instance will be updated based on 
the provided instance.
+     *
+     * @param user an updated user instance
+     * @return the updated user instance, or null if no matching user was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract User updateUser(User user) throws 
AuthorizationAccessException;
+
+    /**
+     * Deletes the given user.
+     *
+     * @param user the user to delete
+     * @return the user that was deleted, or null if no matching user was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract User deleteUser(User user) throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves all users.
+     *
+     * @return a list of users
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Set<User> getUsers() throws AuthorizationAccessException;
+
+
+    /**
+     * Adds the given policy.
+     *
+     * @param accessPolicy the policy to add
+     * @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;
+
+    /**
+     * Retrieves the policy with the given identifier.
+     *
+     * @param identifier the id of the policy to retrieve
+     * @return the policy with the given id, or null if no matching policy 
exists
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract AccessPolicy getAccessPolicy(String identifier) throws 
AuthorizationAccessException;
+
+    /**
+     * The policy represented by the provided instance will be updated based 
on the provided instance.
+     *
+     * @param accessPolicy an updated policy
+     * @return the updated policy, or null if no matching policy was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) 
throws AuthorizationAccessException;
+
+    /**
+     * Deletes the given policy.
+     *
+     * @param policy the policy to delete
+     * @return the deleted policy, or null if no matching policy was found
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract AccessPolicy deleteAccessPolicy(AccessPolicy policy) 
throws AuthorizationAccessException;
+
+    /**
+     * Retrieves all access policies.
+     *
+     * @return a list of policies
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Set<AccessPolicy> getAccessPolicies() throws 
AuthorizationAccessException;
+
+    /**
+     * Retrieves the access policies for the given Resource.
+     *
+     * @param resource the resource to retrieve policies for
+     * @return a set of policies for the given resource, or an empty set if 
there are none
+     * @throws AuthorizationAccessException if there was an unexpected error 
performing the operation
+     */
+    public abstract Set<AccessPolicy> getAccessPolicies(Resource resource) 
throws AuthorizationAccessException;
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/nifi-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java 
b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
new file mode 100644
index 0000000..f5c46e1
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AccessPolicy.java
@@ -0,0 +1,356 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Defines a policy for a set of userIdentifiers to perform a set of actions 
on a given resource.
+ */
+public class AccessPolicy {
+
+    private final String identifier;
+
+    private final Resource resource;
+
+    private final Set<String> users;
+
+    private final Set<String> groups;
+
+    private final Set<RequestAction> actions;
+
+    private AccessPolicy(final AccessPolicyBuilder builder) {
+        this.identifier = builder.identifier;
+        this.resource = builder.resource;
+        this.users = Collections.unmodifiableSet(new HashSet<>(builder.users));
+        this.groups = Collections.unmodifiableSet(new 
HashSet<>(builder.groups));
+        this.actions = Collections.unmodifiableSet(new 
HashSet<>(builder.actions));
+
+        if (this.identifier == null || this.identifier.trim().isEmpty()) {
+            throw new IllegalArgumentException("Identifier can not be null or 
empty");
+        }
+
+        if (this.resource == null) {
+            throw new IllegalArgumentException("Resource can not be null");
+        }
+
+        if ((this.users == null || this.users.isEmpty()) && (this.groups == 
null || this.groups.isEmpty())) {
+            throw new IllegalArgumentException("Users & Groups can not both be 
null or empty");
+        }
+
+        if (this.actions == null || this.actions.isEmpty()) {
+            throw new IllegalArgumentException("Actions can not be null or 
empty");
+        }
+    }
+
+    /**
+     * @return the identifier for this policy
+     */
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * @return the resource for this policy
+     */
+    public Resource getResource() {
+        return resource;
+    }
+
+    /**
+     * @return an unmodifiable set of user ids for this policy
+     */
+    public Set<String> getUsers() {
+        return users;
+    }
+
+    /**
+     * @return an unmodifiable set of group ids for this policy
+     */
+    public Set<String> getGroups() {
+        return groups;
+    }
+
+    /**
+     * @return an unmodifiable set of actions for this policy
+     */
+    public Set<RequestAction> getActions() {
+        return actions;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final AccessPolicy other = (AccessPolicy) obj;
+        return Objects.equals(this.identifier, other.identifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.identifier);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("identifier[%s], resource[%s], users[%s], 
groups[%s], action[%s]",
+                getIdentifier(), getResource().getIdentifier(), getUsers(), 
getGroups(), getActions());
+    }
+
+    /**
+     * Builder for Access Policies.
+     */
+    public static class AccessPolicyBuilder {
+
+        private String identifier;
+        private Resource resource;
+        private Set<String> users = new HashSet<>();
+        private Set<String> groups = new HashSet<>();
+        private Set<RequestAction> actions = new HashSet<>();
+        private final boolean fromPolicy;
+
+        /**
+         * Default constructor for building a new AccessPolicy.
+         */
+        public AccessPolicyBuilder() {
+            this.fromPolicy = false;
+        }
+
+        /**
+         * Initializes the builder with the state of the provided policy. When 
using this constructor
+         * the identifier field of the builder can not be changed and will 
result in an IllegalStateException
+         * if attempting to do so.
+         *
+         * @param other the existing access policy to initialize from
+         */
+        public AccessPolicyBuilder(final AccessPolicy other) {
+            if (other == null) {
+                throw new IllegalArgumentException("Can not initialize builder 
with a null access policy");
+            }
+
+            this.identifier = other.getIdentifier();
+            this.resource = other.getResource();
+            this.users.clear();
+            this.users.addAll(other.getUsers());
+            this.groups.clear();
+            this.groups.addAll(other.getGroups());
+            this.actions.clear();
+            this.actions.addAll(other.getActions());
+            this.fromPolicy = true;
+        }
+
+        /**
+         * Sets the identifier of the builder.
+         *
+         * @param identifier the identifier to set
+         * @return the builder
+         * @throws IllegalStateException if this method is called when this 
builder was constructed from an existing Policy
+         */
+        public AccessPolicyBuilder identifier(final String identifier) {
+            if (fromPolicy) {
+                throw new IllegalStateException(
+                        "Identifier can not be changed when initialized from 
an existing policy");
+            }
+
+            this.identifier = identifier;
+            return this;
+        }
+
+        /**
+         * Sets the resource of the builder.
+         *
+         * @param resource the resource to set
+         * @return the builder
+         */
+        public AccessPolicyBuilder resource(final Resource resource) {
+            this.resource = resource;
+            return this;
+        }
+
+        /**
+         * Adds all the users from the provided set to the builder's set of 
users.
+         *
+         * @param users the users to add
+         * @return the builder
+         */
+        public AccessPolicyBuilder addUsers(final Set<String> users) {
+            if (users != null) {
+                this.users.addAll(users);
+            }
+            return this;
+        }
+
+        /**
+         * Adds the given user to the builder's set of users.
+         *
+         * @param user the user to add
+         * @return the builder
+         */
+        public AccessPolicyBuilder addUser(final String user) {
+            if (user != null) {
+                this.users.add(user);
+            }
+            return this;
+        }
+
+        /**
+         * Removes all users in the provided set from the builder's set of 
users.
+         *
+         * @param users the users to remove
+         * @return the builder
+         */
+        public AccessPolicyBuilder removeUsers(final Set<String> users) {
+            if (users != null) {
+                this.users.removeAll(users);
+            }
+            return this;
+        }
+
+        /**
+         * Removes the provided user from the builder's set of users.
+         *
+         * @param user the user to remove
+         * @return the builder
+         */
+        public AccessPolicyBuilder removeUser(final String user) {
+            if (user != null) {
+                this.users.remove(user);
+            }
+            return this;
+        }
+
+        /**
+         * Clears the builder's set of users so that it is non-null and size 
== 0.
+         *
+         * @return the builder
+         */
+        public AccessPolicyBuilder clearUsers() {
+            this.users.clear();
+            return this;
+        }
+
+        /**
+         * Adds all the groups from the provided set to the builder's set of 
groups.
+         *
+         * @param groups the groups to add
+         * @return the builder
+         */
+        public AccessPolicyBuilder addGroups(final Set<String> groups) {
+            if (groups != null) {
+                this.groups.addAll(groups);
+            }
+            return this;
+        }
+
+        /**
+         * Adds the given group to the builder's set of groups.
+         *
+         * @param group the group to add
+         * @return the builder
+         */
+        public AccessPolicyBuilder 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 AccessPolicyBuilder removeGroups(final Set<String> groups) {
+            if (groups != null) {
+                this.groups.removeAll(groups);
+            }
+            return this;
+        }
+
+        /**
+         * Removes the provided groups from the builder's set of groups.
+         *
+         * @param group the group to remove
+         * @return the builder
+         */
+        public AccessPolicyBuilder removeGroup(final String group) {
+            if (group != null) {
+                this.groups.remove(group);
+            }
+            return this;
+        }
+
+        /**
+         * Clears the builder's set of groups so that it is non-null and size 
== 0.
+         *
+         * @return the builder
+         */
+        public AccessPolicyBuilder clearGroups() {
+            this.groups.clear();
+            return this;
+        }
+
+        /**
+         * Adds the provided action to the builder's set of actions.
+         *
+         * @param action the action to add
+         * @return the builder
+         */
+        public AccessPolicyBuilder addAction(final RequestAction action) {
+            this.actions.add(action);
+            return this;
+        }
+
+        /**
+         * Removes the provided action from the builder's set of actions.
+         *
+         * @param action the action to remove
+         * @return the builder
+         */
+        public AccessPolicyBuilder removeAction(final RequestAction action) {
+            this.actions.remove(action);
+            return this;
+        }
+
+        /**
+         * Clears the builder's set of actions so that it is non-null and size 
== 0.
+         *
+         * @return the builder
+         */
+        public AccessPolicyBuilder clearActions() {
+            this.actions.clear();
+            return this;
+        }
+
+        /**
+         * @return a new AccessPolicy constructed from the state of the builder
+         */
+        public AccessPolicy build() {
+            return new AccessPolicy(this);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/nifi-api/src/main/java/org/apache/nifi/authorization/Group.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/Group.java 
b/nifi-api/src/main/java/org/apache/nifi/authorization/Group.java
new file mode 100644
index 0000000..d7b0f2e
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/Group.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A group that users can belong to.
+ */
+public class Group {
+
+    private final String identifier;
+
+    private final String name;
+
+    private final Set<String> users;
+
+    private Group(final GroupBuilder builder) {
+        this.identifier = builder.identifier;
+        this.name = builder.name;
+        this.users = Collections.unmodifiableSet(new HashSet<>(builder.users));
+
+        if (this.identifier == null || this.identifier.trim().isEmpty()) {
+            throw new IllegalArgumentException("Identifier can not be null or 
empty");
+        }
+
+        if (this.name == null || this.name.trim().isEmpty()) {
+            throw new IllegalArgumentException("Name can not be null or 
empty");
+        }
+    }
+
+    /**
+     * @return the identifier of the group
+     */
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * @return the name of the group
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return an unmodifiable set of user identifiers that belong to this 
group
+     */
+    public Set<String> getUsers() {
+        return users;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final Group other = (Group) obj;
+        return Objects.equals(this.identifier, other.identifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.identifier);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("identifier[%s], name[%s]", getIdentifier(), 
getName());
+    }
+
+
+    /**
+     * Builder for creating Groups.
+     */
+    public static class GroupBuilder {
+
+        private String identifier;
+        private String name;
+        private Set<String> users = new HashSet<>();
+        private final boolean fromGroup;
+
+        public GroupBuilder() {
+            this.fromGroup = false;
+        }
+
+        /**
+         * Initializes the builder with the state of the provided group. When 
using this constructor
+         * the identifier field of the builder can not be changed and will 
result in an IllegalStateException
+         * if attempting to do so.
+         *
+         * @param other the existing access policy to initialize from
+         */
+        public GroupBuilder(final Group other) {
+            if (other == null) {
+                throw new IllegalArgumentException("Provided group can not be 
null");
+            }
+
+            this.identifier = other.getIdentifier();
+            this.name = other.getName();
+            this.users.clear();
+            this.users.addAll(other.getUsers());
+            this.fromGroup = true;
+        }
+
+        /**
+         * Sets the identifier of the builder.
+         *
+         * @param identifier the identifier
+         * @return the builder
+         * @throws IllegalStateException if this method is called when this 
builder was constructed from an existing Group
+         */
+        public GroupBuilder identifier(final String identifier) {
+            if (fromGroup) {
+                throw new IllegalStateException(
+                        "Identifier can not be changed when initialized from 
an existing group");
+            }
+
+            this.identifier = identifier;
+            return this;
+        }
+
+        /**
+         * Sets the name of the builder.
+         *
+         * @param name the name
+         * @return the builder
+         */
+        public GroupBuilder name(final String name) {
+            this.name = name;
+            return this;
+        }
+
+        /**
+         * Adds all users from the provided set to the builder's set of users.
+         *
+         * @param users a set of users to add
+         * @return the builder
+         */
+        public GroupBuilder addUsers(final Set<String> users) {
+            if (users != null) {
+                this.users.addAll(users);
+            }
+            return this;
+        }
+
+        /**
+         * Adds the given user to the builder's set of users.
+         *
+         * @param user the user to add
+         * @return the builder
+         */
+        public GroupBuilder addUser(final String user) {
+            if (user != null) {
+                this.users.add(user);
+            }
+            return this;
+        }
+
+        /**
+         * Removes the given user from the builder's set of users.
+         *
+         * @param user the user to remove
+         * @return the builder
+         */
+        public GroupBuilder removeUser(final String user) {
+            if (user != null) {
+                this.users.remove(user);
+            }
+            return this;
+        }
+
+        /**
+         * Removes all users from the provided set from the builder's set of 
users.
+         *
+         * @param users the users to remove
+         * @return the builder
+         */
+        public GroupBuilder removeUsers(final Set<String> users) {
+            if (users != null) {
+                this.users.removeAll(users);
+            }
+            return this;
+        }
+
+        /**
+         * Clears the builder's set of users so that users is non-null with 
size 0.
+         *
+         * @return the builder
+         */
+        public GroupBuilder clearUsers() {
+            this.users.clear();
+            return this;
+        }
+
+        /**
+         * @return a new Group constructed from the state of the builder
+         */
+        public Group build() {
+            return new Group(this);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/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
new file mode 100644
index 0000000..e068736
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/User.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A user to create authorization policies for.
+ */
+public class User {
+
+    private final String identifier;
+
+    private final String identity;
+
+    private final Set<String> groups;
+
+    private User(final UserBuilder 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");
+        }
+
+        if (identity == null || identity.trim().isEmpty()) {
+            throw new IllegalArgumentException("Identity can not be null or 
empty");
+        }
+
+    }
+
+    /**
+     * @return the identifier of the user
+     */
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * @return the identity string of the user
+     */
+    public String getIdentity() {
+        return identity;
+    }
+
+    /**
+     * @return an unmodifiable set of group ids
+     */
+    public Set<String> getGroups() {
+        return groups;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final User other = (User) obj;
+        return Objects.equals(this.identifier, other.identifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.identifier);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("identifier[%s], identity[%s]", getIdentifier(), 
getIdentity());
+    }
+
+    /**
+     * Builder for Users.
+     */
+    public static class UserBuilder {
+
+        private String identifier;
+        private String identity;
+        private Set<String> groups = new HashSet<>();
+        private final boolean fromUser;
+
+        /**
+         * Default constructor for building a new User.
+         */
+        public UserBuilder() {
+            this.fromUser = false;
+        }
+
+        /**
+         * Initializes the builder with the state of the provided user. When 
using this constructor
+         * the identifier field of the builder can not be changed and will 
result in an IllegalStateException
+         * if attempting to do so.
+         *
+         * @param other the existing user to initialize from
+         */
+        public UserBuilder(final User other) {
+            if (other == null) {
+                throw new IllegalArgumentException("Provided user can not be 
null");
+            }
+
+            this.identifier = other.getIdentifier();
+            this.identity = other.getIdentity();
+            this.groups.clear();
+            this.groups.addAll(other.getGroups());
+            this.fromUser = true;
+        }
+
+        /**
+         * Sets the identifier of the builder.
+         *
+         * @param identifier the identifier to set
+         * @return the builder
+         * @throws IllegalStateException if this method is called when this 
builder was constructed from an existing User
+         */
+        public UserBuilder identifier(final String identifier) {
+            if (fromUser) {
+                throw new IllegalStateException(
+                        "Identifier can not be changed when initialized from 
an existing user");
+            }
+
+            this.identifier = identifier;
+            return this;
+        }
+
+        /**
+         * Sets the identity of the builder.
+         *
+         * @param identity the identity to set
+         * @return the builder
+         */
+        public UserBuilder identity(final String identity) {
+            this.identity = identity;
+            return this;
+        }
+
+        /**
+         * Adds all groups from the provided set to the builder's set of 
groups.
+         *
+         * @param groups the groups to add
+         * @return the builder
+         */
+        public UserBuilder 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 UserBuilder 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 UserBuilder 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 UserBuilder 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 UserBuilder clearGroups() {
+            this.groups.clear();
+            return this;
+        }
+
+        /**
+         * @return a new User constructed from the state of the builder
+         */
+        public User build() {
+            return new User(this);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/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
new file mode 100644
index 0000000..8dbc781
--- /dev/null
+++ 
b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class TestAbstractPolicyBasedAuthorizer {
+
+    static final Resource TEST_RESOURCE = new Resource() {
+        @Override
+        public String getIdentifier() {
+            return "1";
+        }
+
+        @Override
+        public String getName() {
+            return "resource1";
+        }
+    };
+
+    @Test
+    public void testApproveBasedOnUser() {
+        AbstractPolicyBasedAuthorizer authorizer = 
Mockito.mock(AbstractPolicyBasedAuthorizer.class);
+
+        final String userIdentifier = "userIdentifier1";
+        final String userIdentity = "userIdentity1";
+
+        final Set<AccessPolicy> policiesForResource = new HashSet<>();
+        policiesForResource.add(new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser(userIdentifier)
+                .addAction(RequestAction.READ)
+                .build());
+
+        
when(authorizer.getAccessPolicies(TEST_RESOURCE)).thenReturn(policiesForResource);
+
+        final User user = new User.UserBuilder()
+                .identity(userIdentity)
+                .identifier(userIdentifier)
+                .build();
+
+        when(authorizer.getUserByIdentity(userIdentity)).thenReturn(user);
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+                .identity(userIdentity)
+                .resource(TEST_RESOURCE)
+                .action(RequestAction.READ)
+                .accessAttempt(true)
+                .anonymous(false)
+                .build();
+
+        assertEquals(AuthorizationResult.approved(), 
authorizer.authorize(request));
+    }
+
+    @Test
+    public void testApprovedBasedOnGroup() {
+        AbstractPolicyBasedAuthorizer authorizer = 
Mockito.mock(AbstractPolicyBasedAuthorizer.class);
+
+        final String userIdentifier = "userIdentifier1";
+        final String userIdentity = "userIdentity1";
+        final String groupIdentifier = "groupIdentifier1";
+
+        final Set<AccessPolicy> policiesForResource = new HashSet<>();
+        policiesForResource.add(new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addGroup(groupIdentifier)
+                .addAction(RequestAction.READ)
+                .build());
+
+        
when(authorizer.getAccessPolicies(TEST_RESOURCE)).thenReturn(policiesForResource);
+
+        final User user = new User.UserBuilder()
+                .identity(userIdentity)
+                .identifier(userIdentifier)
+                .addGroup(groupIdentifier)
+                .build();
+
+        when(authorizer.getUserByIdentity(userIdentity)).thenReturn(user);
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+                .identity(userIdentity)
+                .resource(TEST_RESOURCE)
+                .action(RequestAction.READ)
+                .accessAttempt(true)
+                .anonymous(false)
+                .build();
+
+        assertEquals(AuthorizationResult.approved(), 
authorizer.authorize(request));
+    }
+
+    @Test
+    public void testDeny() {
+        AbstractPolicyBasedAuthorizer authorizer = 
Mockito.mock(AbstractPolicyBasedAuthorizer.class);
+
+        final String userIdentifier = "userIdentifier1";
+        final String userIdentity = "userIdentity1";
+
+        final Set<AccessPolicy> policiesForResource = new HashSet<>();
+        policiesForResource.add(new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser("NOT_USER_1")
+                .addAction(RequestAction.READ)
+                .build());
+
+        
when(authorizer.getAccessPolicies(TEST_RESOURCE)).thenReturn(policiesForResource);
+
+        final User user = new User.UserBuilder()
+                .identity(userIdentity)
+                .identifier(userIdentifier)
+                .build();
+
+        when(authorizer.getUserByIdentity(userIdentity)).thenReturn(user);
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+                .identity(userIdentity)
+                .resource(TEST_RESOURCE)
+                .action(RequestAction.READ)
+                .accessAttempt(true)
+                .anonymous(false)
+                .build();
+
+        assertEquals(AuthorizationResult.denied().getResult(), 
authorizer.authorize(request).getResult());
+    }
+
+    @Test
+    public void testResourceNotFound() {
+        AbstractPolicyBasedAuthorizer authorizer = 
Mockito.mock(AbstractPolicyBasedAuthorizer.class);
+        when(authorizer.getAccessPolicies(TEST_RESOURCE)).thenReturn(new 
HashSet<>());
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+                .identity("userIdentity")
+                .resource(TEST_RESOURCE)
+                .action(RequestAction.READ)
+                .accessAttempt(true)
+                .anonymous(false)
+                .build();
+
+        assertEquals(AuthorizationResult.resourceNotFound(), 
authorizer.authorize(request));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/nifi-api/src/test/java/org/apache/nifi/authorization/TestAccessPolicy.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/test/java/org/apache/nifi/authorization/TestAccessPolicy.java 
b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAccessPolicy.java
new file mode 100644
index 0000000..28c0b9f
--- /dev/null
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAccessPolicy.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.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;
+import static org.junit.Assert.fail;
+
+public class TestAccessPolicy {
+
+    static final Resource TEST_RESOURCE = new Resource() {
+        @Override
+        public String getIdentifier() {
+            return "1";
+        }
+
+        @Override
+        public String getName() {
+            return "resource1";
+        }
+    };
+
+    @Test
+    public void testSimpleCreation() {
+        final String identifier = "1";
+        final String user1 = "user1";
+        final String user2 = "user2";
+        final RequestAction action = RequestAction.READ;
+
+        final AccessPolicy policy = new AccessPolicy.AccessPolicyBuilder()
+                .identifier(identifier)
+                .resource(TEST_RESOURCE)
+                .addUser(user1)
+                .addUser(user2)
+                .addAction(action)
+                .build();
+
+        assertEquals(identifier, policy.getIdentifier());
+
+        assertNotNull(policy.getResource());
+        assertEquals(TEST_RESOURCE.getIdentifier(), 
policy.getResource().getIdentifier());
+
+        assertNotNull(policy.getUsers());
+        assertEquals(2, policy.getUsers().size());
+        assertTrue(policy.getUsers().contains(user1));
+        assertTrue(policy.getUsers().contains(user2));
+
+        assertNotNull(policy.getActions());
+        assertEquals(1, policy.getActions().size());
+        assertTrue(policy.getActions().contains(action));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingIdentifier() {
+        new AccessPolicy.AccessPolicyBuilder()
+                .resource(TEST_RESOURCE)
+                .addUser("user1")
+                .addAction(RequestAction.READ)
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingResource() {
+        new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .addUser("user1")
+                .addAction(RequestAction.READ)
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingUsersAndGroups() {
+        new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addAction(RequestAction.READ)
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingActions() {
+        new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser("user1")
+                .build();
+    }
+
+    @Test
+    public void testFromPolicy() {
+        final String identifier = "1";
+        final String user1 = "user1";
+        final String user2 = "user2";
+        final String group1 = "group1";
+        final String group2 = "group2";
+        final RequestAction action = RequestAction.READ;
+
+        final AccessPolicy policy = new AccessPolicy.AccessPolicyBuilder()
+                .identifier(identifier)
+                .resource(TEST_RESOURCE)
+                .addUser(user1)
+                .addUser(user2)
+                .addGroup(group1)
+                .addGroup(group2)
+                .addAction(action)
+                .build();
+
+        assertEquals(identifier, policy.getIdentifier());
+
+        assertNotNull(policy.getResource());
+        assertEquals(TEST_RESOURCE.getIdentifier(), 
policy.getResource().getIdentifier());
+
+        assertNotNull(policy.getUsers());
+        assertEquals(2, policy.getUsers().size());
+        assertTrue(policy.getUsers().contains(user1));
+        assertTrue(policy.getUsers().contains(user2));
+
+        assertNotNull(policy.getGroups());
+        assertEquals(2, policy.getGroups().size());
+        assertTrue(policy.getGroups().contains(group1));
+        assertTrue(policy.getGroups().contains(group2));
+
+        assertNotNull(policy.getActions());
+        assertEquals(1, policy.getActions().size());
+        assertTrue(policy.getActions().contains(action));
+
+        final AccessPolicy policy2 = new 
AccessPolicy.AccessPolicyBuilder(policy).build();
+        assertEquals(policy.getIdentifier(), policy2.getIdentifier());
+        assertEquals(policy.getResource().getIdentifier(), 
policy2.getResource().getIdentifier());
+        assertEquals(policy.getUsers(), policy2.getUsers());
+        assertEquals(policy.getActions(), policy2.getActions());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testFromPolicyAndChangeIdentifier() {
+        final AccessPolicy policy = new AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser("user1")
+                .addAction(RequestAction.READ)
+                .build();
+
+        new AccessPolicy.AccessPolicyBuilder(policy).identifier("2").build();
+    }
+
+    @Test
+    public void testAddRemoveClearUsers() {
+        final AccessPolicy.AccessPolicyBuilder builder = new 
AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser("user1")
+                .addAction(RequestAction.READ);
+
+        final AccessPolicy policy1 = builder.build();
+        assertEquals(1, policy1.getUsers().size());
+        assertTrue(policy1.getUsers().contains("user1"));
+
+        final Set<String> moreEntities = new HashSet<>();
+        moreEntities.add("user2");
+        moreEntities.add("user3");
+        moreEntities.add("user4");
+
+        final AccessPolicy policy2 = builder.addUsers(moreEntities).build();
+        assertEquals(4, policy2.getUsers().size());
+        assertTrue(policy2.getUsers().contains("user1"));
+        assertTrue(policy2.getUsers().contains("user2"));
+        assertTrue(policy2.getUsers().contains("user3"));
+        assertTrue(policy2.getUsers().contains("user4"));
+
+        final AccessPolicy policy3 = builder.removeUser("user3").build();
+        assertEquals(3, policy3.getUsers().size());
+        assertTrue(policy3.getUsers().contains("user1"));
+        assertTrue(policy3.getUsers().contains("user2"));
+        assertTrue(policy3.getUsers().contains("user4"));
+
+        final Set<String> removeEntities = new HashSet<>();
+        removeEntities.add("user1");
+        removeEntities.add("user4");
+
+        final AccessPolicy policy4 = 
builder.removeUsers(removeEntities).build();
+        assertEquals(1, policy4.getUsers().size());
+        assertTrue(policy4.getUsers().contains("user2"));
+
+        try {
+            builder.clearUsers().build();
+            fail("should have thrown exception");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+    @Test
+    public void testAddRemoveClearGroups() {
+        final AccessPolicy.AccessPolicyBuilder builder = new 
AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addGroup("group1")
+                .addAction(RequestAction.READ);
+
+        final AccessPolicy policy1 = builder.build();
+        assertEquals(1, policy1.getGroups().size());
+        assertTrue(policy1.getGroups().contains("group1"));
+
+        final Set<String> moreGroups = new HashSet<>();
+        moreGroups.add("group2");
+        moreGroups.add("group3");
+        moreGroups.add("group4");
+
+        final AccessPolicy policy2 = builder.addGroups(moreGroups).build();
+        assertEquals(4, policy2.getGroups().size());
+        assertTrue(policy2.getGroups().contains("group1"));
+        assertTrue(policy2.getGroups().contains("group2"));
+        assertTrue(policy2.getGroups().contains("group3"));
+        assertTrue(policy2.getGroups().contains("group4"));
+
+        final AccessPolicy policy3 = builder.removeGroup("group3").build();
+        assertEquals(3, policy3.getGroups().size());
+        assertTrue(policy3.getGroups().contains("group1"));
+        assertTrue(policy3.getGroups().contains("group2"));
+        assertTrue(policy3.getGroups().contains("group4"));
+
+        final Set<String> removeGroups = new HashSet<>();
+        removeGroups.add("group1");
+        removeGroups.add("group4");
+
+        final AccessPolicy policy4 = 
builder.removeGroups(removeGroups).build();
+        assertEquals(1, policy4.getGroups().size());
+        assertTrue(policy4.getGroups().contains("group2"));
+
+        try {
+            builder.clearGroups().build();
+            fail("should have thrown exception");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+
+    @Test
+    public void testAddRemoveClearActions() {
+        final AccessPolicy.AccessPolicyBuilder builder = new 
AccessPolicy.AccessPolicyBuilder()
+                .identifier("1")
+                .resource(TEST_RESOURCE)
+                .addUser("user1")
+                .addAction(RequestAction.READ);
+
+        final AccessPolicy policy1 = builder.build();
+        assertEquals(1, policy1.getActions().size());
+        assertTrue(policy1.getActions().contains(RequestAction.READ));
+
+        final AccessPolicy policy2 = builder
+                .removeAction(RequestAction.READ)
+                .addAction(RequestAction.WRITE)
+                .build();
+
+        assertEquals(1, policy2.getActions().size());
+        assertTrue(policy2.getActions().contains(RequestAction.WRITE));
+
+        try {
+            builder.clearActions().build();
+            fail("should have thrown exception");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/nifi-api/src/test/java/org/apache/nifi/authorization/TestGroup.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/test/java/org/apache/nifi/authorization/TestGroup.java 
b/nifi-api/src/test/java/org/apache/nifi/authorization/TestGroup.java
new file mode 100644
index 0000000..39dbab6
--- /dev/null
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestGroup.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.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 TestGroup {
+
+    @Test
+    public void testSimpleCreation() {
+        final String id = "1";
+        final String name = "group1";
+        final String user1 = "user1";
+        final String user2 = "user2";
+
+        final Group group = new Group.GroupBuilder()
+                .identifier(id)
+                .name(name)
+                .addUser(user1)
+                .addUser(user2)
+                .build();
+
+        assertEquals(id, group.getIdentifier());
+        assertEquals(name, group.getName());
+
+        assertNotNull(group.getUsers());
+        assertEquals(2, group.getUsers().size());
+        assertTrue(group.getUsers().contains(user1));
+        assertTrue(group.getUsers().contains(user2));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingId() {
+        new Group.GroupBuilder()
+                .name("group1")
+                .addUser("user1")
+                .addUser("user2")
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingName() {
+        new Group.GroupBuilder()
+                .identifier("1")
+                .addUser("user1")
+                .addUser("user2")
+                .build();
+    }
+
+    @Test
+    public void testMissingUsers() {
+        final String id = "1";
+        final String name = "group1";
+
+        final Group group = new Group.GroupBuilder()
+                .identifier(id)
+                .name(name)
+                .build();
+
+        assertEquals(id, group.getIdentifier());
+        assertEquals(name, group.getName());
+
+        assertNotNull(group.getUsers());
+        assertEquals(0, group.getUsers().size());
+    }
+
+    @Test
+    public void testFromGroup() {
+        final String id = "1";
+        final String name = "group1";
+        final String user1 = "user1";
+        final String user2 = "user2";
+
+        final Group group1 = new Group.GroupBuilder()
+                .identifier(id)
+                .name(name)
+                .addUser(user1)
+                .addUser(user2)
+                .build();
+
+        assertEquals(id, group1.getIdentifier());
+        assertEquals(name, group1.getName());
+
+        assertNotNull(group1.getUsers());
+        assertEquals(2, group1.getUsers().size());
+        assertTrue(group1.getUsers().contains(user1));
+        assertTrue(group1.getUsers().contains(user2));
+
+        final Group group2 = new Group.GroupBuilder(group1).build();
+        assertEquals(group1.getIdentifier(), group2.getIdentifier());
+        assertEquals(group1.getName(), group2.getName());
+        assertEquals(group1.getUsers(), group2.getUsers());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testFromGroupAndChangeIdentifier() {
+        final Group group1 = new Group.GroupBuilder()
+                .identifier("1")
+                .name("group1")
+                .addUser("user1")
+                .build();
+
+        new Group.GroupBuilder(group1).identifier("2").build();
+    }
+
+    @Test
+    public void testAddRemoveClearUsers() {
+        final Group.GroupBuilder builder = new Group.GroupBuilder()
+                .identifier("1")
+                .name("group1")
+                .addUser("user1");
+
+        final Group group1 = builder.build();
+        assertNotNull(group1.getUsers());
+        assertEquals(1, group1.getUsers().size());
+        assertTrue(group1.getUsers().contains("user1"));
+
+        final Set<String> moreUsers = new HashSet<>();
+        moreUsers.add("user2");
+        moreUsers.add("user3");
+        moreUsers.add("user4");
+
+        final Group group2 = builder.addUsers(moreUsers).build();
+        assertEquals(4, group2.getUsers().size());
+        assertTrue(group2.getUsers().contains("user1"));
+        assertTrue(group2.getUsers().contains("user2"));
+        assertTrue(group2.getUsers().contains("user3"));
+        assertTrue(group2.getUsers().contains("user4"));
+
+        final Group group3 = builder.removeUser("user2").build();
+        assertEquals(3, group3.getUsers().size());
+        assertTrue(group3.getUsers().contains("user1"));
+        assertTrue(group3.getUsers().contains("user3"));
+        assertTrue(group3.getUsers().contains("user4"));
+
+        final Set<String> removeUsers = new HashSet<>();
+        removeUsers.add("user1");
+        removeUsers.add("user4");
+
+        final Group group4 = builder.removeUsers(removeUsers).build();
+        assertEquals(1, group4.getUsers().size());
+        assertTrue(group4.getUsers().contains("user3"));
+
+        final Group group5 = builder.clearUsers().build();
+        assertEquals(0, group5.getUsers().size());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/71492535/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
new file mode 100644
index 0000000..8e6f9aa
--- /dev/null
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestUser.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.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 {
+
+    @Test
+    public void testSimpleCreation() {
+        final String identifier = "1";
+        final String identity = "user1";
+        final String group1 = "group1";
+        final String group2 = "group2";
+
+        final User user = new User.UserBuilder()
+                .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.UserBuilder()
+                .identity("user1")
+                .addGroup("group1")
+                .addGroup("group2")
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingIdentity() {
+        new User.UserBuilder()
+                .identifier("1")
+                .addGroup("group1")
+                .addGroup("group2")
+                .build();
+    }
+
+    @Test
+    public void testMissingGroups() {
+        final String identifier = "1";
+        final String identity = "user1";
+
+        final User user = new User.UserBuilder()
+                .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";
+        final String group1 = "group1";
+        final String group2 = "group2";
+
+        final User user = new User.UserBuilder()
+                .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.UserBuilder(user).build();
+        assertEquals(user.getIdentifier(), user2.getIdentifier());
+        assertEquals(user.getIdentity(), user2.getIdentity());
+        assertEquals(user.getGroups(), user2.getGroups());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testFromUserAndChangeIdentifier() {
+        final User user = new User.UserBuilder()
+                .identifier("1")
+                .identity("user1")
+                .addGroup("group1")
+                .addGroup("group2")
+                .build();
+
+        new User.UserBuilder(user).identifier("2").build();
+    }
+
+    @Test
+    public void testAddRemoveClearGroups() {
+        final User.UserBuilder builder = new User.UserBuilder()
+                .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());
+    }
+
+}

Reply via email to