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
This commit is contained in:
Bryan Bende 2016-07-05 16:16:08 -04:00 committed by Matt Gilman
parent f4c94e349c
commit c5889314ca
16 changed files with 311 additions and 531 deletions

View File

@ -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";
@ -61,6 +62,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();
@ -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();
}

View File

@ -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;
}
@ -155,68 +139,6 @@ public class User {
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 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
*/

View File

@ -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);
}

View File

@ -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 {
}

View File

@ -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,28 +49,9 @@ 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";
@ -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());
}
}

View File

@ -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);
}

View File

@ -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());
}
@ -198,32 +197,6 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
return allGroups;
}
/**
* 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.
*
@ -287,6 +260,32 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
return groupsMap;
}
/**
* 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.
*
@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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));

View File

@ -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">

View File

@ -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();
try {
final AccessPolicy returnedPolicy2 = authorizer.addAccessPolicy(policy2);
assertNotNull(returnedPolicy2);
assertEquals(2, authorizer.getAccessPolicies().size());
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"));

View File

@ -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)

View File

@ -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());

View File

@ -45,6 +45,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.
*

View File

@ -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
@ -219,6 +219,13 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
return userGroup;
}
@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();
}

View File

@ -16,19 +16,12 @@
*/
package org.apache.nifi.web.dao.impl
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer
import org.apache.nifi.authorization.AccessPolicy
import org.apache.nifi.authorization.Authorizer
import org.apache.nifi.authorization.Group
import org.apache.nifi.authorization.RequestAction
import org.apache.nifi.authorization.User
import org.apache.nifi.authorization.*
import org.apache.nifi.web.ResourceNotFoundException
import org.apache.nifi.web.api.dto.AccessPolicyDTO
import org.apache.nifi.web.api.dto.UserDTO
import org.apache.nifi.web.api.dto.UserGroupDTO
import org.apache.nifi.web.api.entity.TenantEntity
import org.apache.nifi.web.api.entity.UserEntity
import org.apache.nifi.web.api.entity.UserGroupEntity
import spock.lang.Specification
import spock.lang.Unroll
@ -100,14 +93,15 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
noExceptionThrown()
then:
1 * authorizer.addAccessPolicy(accessPolicy) >> accessPolicy
1 * authorizer.getAccessPolicies() >> accessPolicies
1 * authorizer.doAddAccessPolicy(accessPolicy) >> accessPolicy
0 * _
result?.equals accessPolicy
where:
accessPolicy | _
accessPolicy | accessPolicies
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.action(RequestAction.WRITE).build() | _
.action(RequestAction.WRITE).build() | [] as Set
}
@Unroll
@ -409,7 +403,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
new User.Builder().identifier('user-id-1').identity('user identity').build() | _
}
@Unroll
@ -432,7 +426,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
new User.Builder().identifier('user-id-1').identity('user identity').build() | _
}
@Unroll
@ -451,7 +445,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
new User.Builder().identifier('user-id-1').identity('user identity').build() | _
}
@Unroll
@ -485,7 +479,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
users | _
[new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build()] as Set | _
[new User.Builder().identifier('user-id-1').identity('user identity').build()] as Set | _
}
@Unroll
@ -506,7 +500,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
new User.Builder().identifier('user-id-1').identity('user identity').build() | _
}
@Unroll
@ -542,7 +536,7 @@ class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
new User.Builder().identifier('user-id-1').identity('user identity').build() | _
}
@Unroll