NIFI-1952 Updated StandardPolicyBasedAuthorizerDAO to throw ResourceNotFoundExceptions when user/group/policy not found

Added spec for StandardPolicyBasedAuthorizerDAO
Added exception mapper for AuthorizationAccessException, added mapper to nifi-web-api-context.xml
Added rest endpoints to get all users and user groups
Merged UsersResource and UserGroupsResource into TenantsResource
This closes #582
This commit is contained in:
Jeff Storck 2016-06-22 20:47:53 -04:00 committed by Matt Gilman
parent b911c9dbdf
commit 64719b6f9b
23 changed files with 1671 additions and 974 deletions

View File

@ -29,7 +29,7 @@ import java.util.Set;
public class UserDTO extends ComponentDTO {
private String identity;
private Set<UserGroupEntity> groups;
private Set<UserGroupEntity> userGroups;
/**
* @return users identity
@ -49,11 +49,11 @@ public class UserDTO extends ComponentDTO {
* @return groups to which the user belongs
*/
@ApiModelProperty(value = "The groups to which the user belongs.")
public Set<UserGroupEntity> getGroups() {
return groups;
public Set<UserGroupEntity> getUserGroups() {
return userGroups;
}
public void setGroups(Set<UserGroupEntity> groups) {
this.groups = groups;
public void setUserGroups(Set<UserGroupEntity> userGroups) {
this.userGroups = userGroups;
}
}

View File

@ -14,18 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.authorization.resource;
package org.apache.nifi.web.api.entity;
import org.apache.nifi.authorization.Resource;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Collection;
public class UserGroupsAuthorizable implements Authorizable {
@Override
public Authorizable getParentAuthorizable() {
return null;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a collection of
* UserGroupEntity objects.
*/
@XmlRootElement(name = "userGroupsEntity")
public class UserGroupsEntity {
private Collection<UserGroupEntity> userGroups;
/**
* The collection of UserGroupEntity objects that are being serialized.
*
* @return The UserGroupEntity objects
*/
public Collection<UserGroupEntity> getUserGroups() {
return userGroups;
}
@Override
public Resource getResource() {
return ResourceFactory.getUserGroupsResource();
public void setUserGroups(Collection<UserGroupEntity> userGroups) {
this.userGroups = userGroups;
}
}

View File

@ -16,45 +16,28 @@
*/
package org.apache.nifi.web.api.entity;
import java.util.Collection;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.util.TimeAdapter;
import java.util.Collection;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a collection of UserDTO.
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a collection of UserEntity
* objects.
*/
@XmlRootElement(name = "usersEntity")
public class UsersEntity extends Entity {
private Collection<UserDTO> users;
private Date generated;
private Collection<UserEntity> users;
/**
* The collection of UserDTOs that are being serialized.
* The collection of UserEntity objects that are being serialized.
*
* @return The UserDTO object
* @return The UserEntity objects
*/
public Collection<UserDTO> getUsers() {
public Collection<UserEntity> getUsers() {
return users;
}
public void setUsers(Collection<UserDTO> users) {
public void setUsers(Collection<UserEntity> users) {
this.users = users;
}
/**
* @return When this content was generated
*/
@XmlJavaTypeAdapter(TimeAdapter.class)
public Date getGenerated() {
return generated;
}
public void setGenerated(Date generated) {
this.generated = generated;
}
}

View File

@ -327,11 +327,8 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
addAccessPolicy(authorizations, ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, adminUser.getIdentifier(), READ_CODE + WRITE_CODE);
}
// grant the user read/write access to the /users resource
addAccessPolicy(authorizations, ResourceType.User.getValue(), adminUser.getIdentifier(), READ_CODE + WRITE_CODE);
// grant the user read/write access to the /groups resource
addAccessPolicy(authorizations, ResourceType.Group.getValue(), adminUser.getIdentifier(), READ_CODE + WRITE_CODE);
// grant the user read/write access to the /tenants resource
addAccessPolicy(authorizations, ResourceType.Tenant.getValue(), adminUser.getIdentifier(), READ_CODE + WRITE_CODE);
// grant the user read/write access to the /policies resource
addAccessPolicy(authorizations, ResourceType.Policy.getValue(), adminUser.getIdentifier(), READ_CODE + WRITE_CODE);

View File

@ -79,8 +79,7 @@ public final class RoleAccessPolicy {
if (rootGroupId != null) {
adminPolicies.add(new RoleAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + rootGroupId, READ_ACTION));
}
adminPolicies.add(new RoleAccessPolicy(ResourceType.User.getValue(), READ_WRITE_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Group.getValue(), READ_WRITE_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Tenant.getValue(), READ_WRITE_ACTION));
adminPolicies.add(new RoleAccessPolicy(ResourceType.Policy.getValue(), READ_WRITE_ACTION));
roleAccessPolicies.put(Role.ROLE_ADMIN, Collections.unmodifiableSet(adminPolicies));

View File

@ -235,7 +235,7 @@ public class FileAuthorizerTest {
// verify user4's policies
final Map<String,Set<RequestAction>> user4Policies = getResourceActions(policies, user4);
assertEquals(6, user4Policies.size());
assertEquals(5, user4Policies.size());
assertTrue(user4Policies.containsKey(ResourceType.Flow.getValue()));
assertEquals(1, user4Policies.get(ResourceType.Flow.getValue()).size());
@ -245,11 +245,8 @@ public class FileAuthorizerTest {
assertEquals(1, user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
assertTrue(user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
assertTrue(user4Policies.containsKey(ResourceType.User.getValue()));
assertEquals(2, user4Policies.get(ResourceType.User.getValue()).size());
assertTrue(user4Policies.containsKey(ResourceType.Group.getValue()));
assertEquals(2, user4Policies.get(ResourceType.Group.getValue()).size());
assertTrue(user4Policies.containsKey(ResourceType.Tenant.getValue()));
assertEquals(2, user4Policies.get(ResourceType.Tenant.getValue()).size());
assertTrue(user4Policies.containsKey(ResourceType.Policy.getValue()));
assertEquals(2, user4Policies.get(ResourceType.Policy.getValue()).size());
@ -338,7 +335,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
assertEquals(5, policies.size());
assertEquals(4, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
@ -375,7 +372,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
assertEquals(4, policies.size());
assertEquals(3, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
@ -412,7 +409,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
assertEquals(4, policies.size());
assertEquals(3, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;

View File

@ -17,9 +17,7 @@
package org.apache.nifi.authorization.resource;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.User;
import java.util.Objects;
@ -85,18 +83,6 @@ public final class ResourceFactory {
}
};
private final static Resource GROUP_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return ResourceType.Group.getValue();
}
@Override
public String getName() {
return "Group";
}
};
private final static Resource INPUT_PORT_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
@ -277,6 +263,18 @@ public final class ResourceFactory {
}
};
private final static Resource TENANT_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return ResourceType.Tenant.getValue();
}
@Override
public String getName() {
return "Tenant";
}
};
private final static Resource TOKEN_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
@ -289,18 +287,6 @@ public final class ResourceFactory {
}
};
private final static Resource USER_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return ResourceType.User.getValue();
}
@Override
public String getName() {
return "User";
}
};
private final static Resource POLICIES_RESOURCE = new Resource() {
@Override
@ -314,32 +300,6 @@ public final class ResourceFactory {
}
};
private final static Resource USERS_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return "/users";
}
@Override
public String getName() {
return "Users";
}
};
private final static Resource USERGROUPS_RESOURCE = new Resource() {
@Override
public String getIdentifier() {
return "/user-groups";
}
@Override
public String getName() {
return "User Groups";
}
};
/**
* Gets the Resource for accessing Connections.
*
@ -385,15 +345,6 @@ public final class ResourceFactory {
return FLOW_RESOURCE;
}
/**
* Gets the Resource for accessing Groups which allows management of user groups.
*
* @return The resource for accessing Groups
*/
public static Resource getGroupResource() {
return GROUP_RESOURCE;
}
/**
* Gets the Resource for accessing Input Ports.
*
@ -541,12 +492,12 @@ public final class ResourceFactory {
}
/**
* Gets the Resource for accessing Users which includes creating, modifying, and deleting Users.
* Gets the Resource for accessing Tenants which includes creating, modifying, and deleting Users and UserGroups.
*
* @return The Resource for accessing Users
* @return The Resource for accessing Tenants
*/
public static Resource getUserResource() {
return USER_RESOURCE;
public static Resource getTenantResource() {
return TENANT_RESOURCE;
}
/**
@ -602,24 +553,6 @@ public final class ResourceFactory {
};
}
/**
* Gets a Resource for accessing {@link User} configurations.
*
* @return The resource
*/
public static Resource getUsersResource() {
return USERS_RESOURCE;
}
/**
* Gets a Resource for accessing {@link Group}s configuration.
*
* @return The resource
*/
public static Resource getUserGroupsResource() {
return USERGROUPS_RESOURCE;
}
/**
* Gets a Resource for accessing a component configuration.
*

View File

@ -20,9 +20,9 @@ public enum ResourceType {
Connection("/connections"),
Controller("/controller"),
ControllerService("/controller-services"),
Counters("/counters"),
Funnel("/funnel"),
Flow("/flow"),
Group("/groups"),
InputPort("/input-ports"),
Label("/labels"),
OutputPort("/output-ports"),
@ -37,9 +37,8 @@ public enum ResourceType {
SiteToSite("/site-to-site"),
System("/system"),
Template("/templates"),
Token("/token"),
Counters("/counters"),
User("/users");
Tenant("/tenants"),
Token("/token");
final String value;

View File

@ -18,7 +18,7 @@ package org.apache.nifi.authorization.resource;
import org.apache.nifi.authorization.Resource;
public class UsersAuthorizable implements Authorizable {
public class TenantAuthorizable implements Authorizable {
@Override
public Authorizable getParentAuthorizable() {
@ -27,7 +27,7 @@ public class UsersAuthorizable implements Authorizable {
@Override
public Resource getResource() {
return ResourceFactory.getUsersResource();
return ResourceFactory.getTenantResource();
}
}

View File

@ -17,8 +17,6 @@
package org.apache.nifi.web;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.controller.Snippet;
@ -163,16 +161,10 @@ public interface AuthorizableLookup {
Snippet getSnippet(String id);
/**
* Get the {@link Authorizable} that represents the resource of {@link User}s.
* Get the {@link Authorizable} that represents the resource of users and user groups.
* @return authorizable
*/
Authorizable getUsersAuthorizable();
/**
* Get the {@link Authorizable} that represents the resource of {@link Group}s.
* @return authorizable
*/
Authorizable getUserGroupsAuthorizable();
Authorizable getTenantAuthorizable();
/**
* Get the {@link Authorizable} the represents the parent resource of {@link AccessPolicy} resources.

View File

@ -1220,6 +1220,13 @@ public interface NiFiServiceFacade {
*/
UserEntity getUser(String userId, boolean prune);
/**
* Gets all the users.
* @param prune If true, the users in the groups to which the users belong will not be returned
* @return The user transfer objects
*/
Set<UserEntity> getUsers(boolean prune);
/**
* Updates the specified user.
* @param revision Revision to compare with current base revision
@ -1255,6 +1262,13 @@ public interface NiFiServiceFacade {
*/
UserGroupEntity getUserGroup(String userGroupId, boolean prune);
/**
* Gets all user groups.
* @param prune If true, the user groups of the users in the user groups will not be returned
* @return The user group transfer objects
*/
Set<UserGroupEntity> getUserGroups(boolean prune);
/**
* Updates the specified user group.
* @param revision Revision to compare with current base revision

View File

@ -19,8 +19,7 @@ package org.apache.nifi.web;
import org.apache.nifi.authorization.resource.AccessPoliciesAuthorizable;
import org.apache.nifi.authorization.resource.AccessPolicyAuthorizable;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.UserGroupsAuthorizable;
import org.apache.nifi.authorization.resource.UsersAuthorizable;
import org.apache.nifi.authorization.resource.TenantAuthorizable;
import org.apache.nifi.controller.ConfiguredComponent;
import org.apache.nifi.controller.Snippet;
import org.apache.nifi.controller.service.ControllerServiceNode;
@ -44,8 +43,7 @@ import org.apache.nifi.web.dao.TemplateDAO;
class StandardAuthorizableLookup implements AuthorizableLookup {
private static final UsersAuthorizable USERS_AUTHORIZABLE = new UsersAuthorizable();
private static final UserGroupsAuthorizable USER_GROUPS_AUTHORIZABLE = new UserGroupsAuthorizable();
private static final TenantAuthorizable TENANT_AUTHORIZABLE = new TenantAuthorizable();
private static final Authorizable ACCESS_POLICIES_AUTHORIZABLE = new AccessPoliciesAuthorizable();
// nifi core components
@ -159,13 +157,8 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
}
@Override
public Authorizable getUsersAuthorizable() {
return USERS_AUTHORIZABLE;
}
@Override
public Authorizable getUserGroupsAuthorizable() {
return USER_GROUPS_AUTHORIZABLE;
public Authorizable getTenantAuthorizable() {
return TENANT_AUTHORIZABLE;
}
@Override

View File

@ -535,7 +535,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override
public UserEntity updateUser(final Revision revision, final UserDTO userDTO) {
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
final Authorizable usersAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionUpdate<UserDTO> snapshot = updateComponent(revision,
usersAuthorizable,
() -> userDAO.updateUser(userDTO),
@ -547,7 +547,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override
public UserGroupEntity updateUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) {
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
final Authorizable userGroupsAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionUpdate<UserGroupDTO> snapshot = updateComponent(revision,
userGroupsAuthorizable,
() -> userGroupDAO.updateUserGroup(userGroupDTO),
@ -985,7 +985,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final Set<UserGroupEntity> userGroups = user != null ? user.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()) : null;
final UserDTO snapshot = deleteComponent(
revision,
authorizableLookup.getUsersAuthorizable(),
authorizableLookup.getTenantAuthorizable(),
() -> userDAO.deleteUser(userId),
dtoFactory.createUserDto(user, userGroups));
@ -999,7 +999,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
null;
final UserGroupDTO snapshot = deleteComponent(
revision,
authorizableLookup.getUserGroupsAuthorizable(),
authorizableLookup.getTenantAuthorizable(),
() -> userGroupDAO.deleteUserGroup(userGroupId),
dtoFactory.createUserGroupDto(userGroup, users));
@ -1283,7 +1283,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final User newUser = userDAO.createUser(userDTO);
final UserDTO newUserDto = dtoFactory.createUserDto(newUser, newUser.getGroups().stream().map(userGroupId -> getUserGroup(userGroupId, true)).collect(Collectors.toSet()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getUsersAuthorizable());
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getTenantAuthorizable());
return entityFactory.createUserEntity(newUserDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
}
@ -1296,7 +1296,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final Group newUserGroup = userGroupDAO.createUserGroup(userGroupDTO);
final UserGroupDTO newUserGroupDto = dtoFactory.createUserGroupDto(newUserGroup, newUserGroup.getUsers().stream().map(userId -> getUser(userId, true)).collect(Collectors.toSet()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getUserGroupsAuthorizable());
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(authorizableLookup.getTenantAuthorizable());
return entityFactory.createUserGroupEntity(newUserGroupDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), accessPolicy);
}
@ -2354,7 +2354,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override
public UserEntity getUser(final String userId, final boolean prune) {
return revisionManager.get(userId, rev -> {
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
final Authorizable usersAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
final User user = userDAO.getUser(userId);
@ -2367,7 +2367,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
private UserEntity getUserPruned(final String userId) {
return revisionManager.get(userId, rev -> {
final Authorizable usersAuthorizable = authorizableLookup.getUsersAuthorizable();
final Authorizable usersAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(usersAuthorizable);
final User user = userDAO.getUser(userId);
@ -2375,10 +2375,29 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
});
}
@Override
public Set<UserEntity> getUsers(boolean prune) {
final Authorizable userAuthorizable = authorizableLookup.getTenantAuthorizable();
final Set<User> users = userDAO.getUsers();
final Set<String> ids = users.stream().map(user -> user.getIdentifier()).collect(Collectors.toSet());
return revisionManager.get(ids, () -> {
return users.stream()
.map(user -> {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(user.getIdentifier()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userAuthorizable);
final Set<UserGroupEntity> userGroups = user.getGroups().stream()
.map(userGroupId -> prune ? getUserGroupPruned(userGroupId) : getUserGroup(userGroupId, false))
.collect(Collectors.toSet());
return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups), revision, accessPolicy);
})
.collect(Collectors.toSet());
});
}
@Override
public UserGroupEntity getUserGroup(final String userGroupId, final boolean prune) {
return revisionManager.get(userGroupId, rev -> {
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
final Authorizable userGroupsAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable);
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
@ -2390,7 +2409,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
private UserGroupEntity getUserGroupPruned(final String userGroupId) {
return revisionManager.get(userGroupId, rev -> {
final Authorizable userGroupsAuthorizable = authorizableLookup.getUserGroupsAuthorizable();
final Authorizable userGroupsAuthorizable = authorizableLookup.getTenantAuthorizable();
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupsAuthorizable);
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
@ -2398,6 +2417,25 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
});
}
@Override
public Set<UserGroupEntity> getUserGroups(boolean prune) {
final Authorizable userGroupAuthorizable = authorizableLookup.getTenantAuthorizable();
final Set<Group> userGroups = userGroupDAO.getUserGroups();
final Set<String> ids = userGroups.stream().map(userGroup -> userGroup.getIdentifier()).collect(Collectors.toSet());
return revisionManager.get(ids, () -> {
return userGroups.stream()
.map(userGroup -> {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userGroup.getIdentifier()));
final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(userGroupAuthorizable);
final Set<UserEntity> users = userGroup.getUsers().stream()
.map(userGroupId -> prune ? getUserPruned(userGroupId) : getUser(userGroupId, false))
.collect(Collectors.toSet());
return entityFactory.createUserGroupEntity(dtoFactory.createUserGroupDto(userGroup, users), revision, accessPolicy);
})
.collect(Collectors.toSet());
});
}
@Override
public Set<LabelEntity> getLabels(final String groupId) {
final Set<Label> labels = labelDAO.getLabels(groupId);

View File

@ -0,0 +1,848 @@
/*
* 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.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.api.entity.UserGroupsEntity;
import org.apache.nifi.web.api.entity.UsersEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.Set;
@Path("tenants")
@Api(
value = "tenants",
description = "Endpoint for managing users and user groups."
)
public class TenantsResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public TenantsResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified users.
*
* @param userEntities users
* @return user entities
*/
public Set<UserEntity> populateRemainingUserEntitiesContent(Set<UserEntity> userEntities) {
for (UserEntity userEntity : userEntities) {
populateRemainingUserEntityContent(userEntity);
}
return userEntities;
}
/**
* Populates the uri for the specified user.
*
* @param userEntity userEntity
* @return userEntity
*/
public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) {
if (userEntity.getComponent() != null) {
populateRemainingUserContent(userEntity.getComponent());
}
return userEntity;
}
/**
* Populates the uri for the specified user.
*/
public UserDTO populateRemainingUserContent(UserDTO user) {
// populate the user href
user.setUri(generateResourceUri("tenants/users", user.getId()));
return user;
}
/**
* Populates the uri for the specified users.
*
* @param users users
* @return user data transfer objects
*/
public Set<UserDTO> populateRemainingUsersContent(Set<UserDTO> users) {
for (UserDTO userDTO : users) {
populateRemainingUserContent(userDTO);
}
return users;
}
/**
* Creates a new user.
*
* @param httpServletRequest request
* @param userEntity An userEntity.
* @return An userEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("users")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getRevision() == null || (userEntity.getRevision().getVersion() == null || userEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Processor.");
}
if (userEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getTenantAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user id as appropriate
userEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userEntity.getComponent().getId());
// create the user and generate the json
final UserEntity entity = serviceFacade.createUser(revision, userEntity.getComponent());
populateRemainingUserEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user.
*
* @param id The id of the user to retrieve
* @return An userEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("users/{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUser(
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getTenantAuthorizable();
users.authorize(authorizer, RequestAction.READ);
});
// get the user
final UserEntity entity = serviceFacade.getUser(id, true);
populateRemainingUserEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Retrieves all the of users in this NiFi.
*
* @return A UsersEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("users")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets all users",
response = UsersEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUsers() {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getTenantAuthorizable();
users.authorize(authorizer, RequestAction.READ);
});
// get all the users
final Set<UserEntity> users = serviceFacade.getUsers(true);
// create the response entity
final UsersEntity entity = new UsersEntity();
entity.setUsers(populateRemainingUserEntitiesContent(users));
// generate the response
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user.
*
* @param httpServletRequest request
* @param id The id of the user to update.
* @param userEntity An userEntity.
* @return An userEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("users/{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserDTO userDTO = userEntity.getComponent();
if (!id.equals(userDTO.getId())) {
throw new IllegalArgumentException(String.format("The user id (%s) in the request body does not equal the "
+ "user id of the requested resource (%s).", userDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userEntity);
}
// Extract the revision
final Revision revision = getRevision(userEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getTenantAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user
final UserEntity entity = serviceFacade.updateUser(revision, userDTO);
populateRemainingUserEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
/**
* Removes the specified user.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("users/{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getTenantAuthorizable();
users.authorize(authorizer, RequestAction.READ);
},
null,
() -> {
// delete the specified user
final UserEntity entity = serviceFacade.deleteUser(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
/**
* Populates the uri for the specified user groups.
*
* @param userGroupEntities user groups
* @return user group entities
*/
public Set<UserGroupEntity> populateRemainingUserGroupEntitiesContent(Set<UserGroupEntity> userGroupEntities) {
for (UserGroupEntity userGroupEntity : userGroupEntities) {
populateRemainingUserGroupEntityContent(userGroupEntity);
}
return userGroupEntities;
}
/**
* Populates the uri for the specified user group.
*
* @param userGroupEntity userGroupEntity
* @return userGroupEntity
*/
public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
if (userGroupEntity.getComponent() != null) {
populateRemainingUserGroupContent(userGroupEntity.getComponent());
}
return userGroupEntity;
}
/**
* Populates the uri for the specified userGroup.
*/
public UserGroupDTO populateRemainingUserGroupContent(UserGroupDTO userGroup) {
// populate the user group href
userGroup.setUri(generateResourceUri("tenants/user-groups", userGroup.getId()));
return userGroup;
}
/**
* Populates the uri for the specified user groups.
*
* @param userGroups user groups
* @return user group data transfer objects
*/
public Set<UserGroupDTO> populateRemainingUserGroupsContent(Set<UserGroupDTO> userGroups) {
for (UserGroupDTO userGroup : userGroups) {
populateRemainingUserGroupContent(userGroup);
}
return userGroups;
}
/**
* Creates a new user group.
*
* @param httpServletRequest request
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("user-groups")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getRevision() == null || (userGroupEntity.getRevision().getVersion() == null || userGroupEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Processor.");
}
if (userGroupEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User group ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userGroupEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getTenantAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user group id as appropriate
userGroupEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userGroupEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userGroupEntity.getComponent().getId());
// create the user group and generate the json
final UserGroupEntity entity = serviceFacade.createUserGroup(revision, userGroupEntity.getComponent());
populateRemainingUserGroupEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user group.
*
* @param id The id of the user group to retrieve
* @return An userGroupEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("user-groups/{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUserGroup(
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getTenantAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
});
// get the user group
final UserGroupEntity entity = serviceFacade.getUserGroup(id, true);
populateRemainingUserGroupEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Retrieves all the of user groups in this NiFi.
*
* @return A UserGroupsEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("user-groups")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets all user groups",
response = UserGroupsEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUserGroups() {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getTenantAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
});
// get all the user groups
final Set<UserGroupEntity> users = serviceFacade.getUserGroups(true);
// create the response entity
final UserGroupsEntity entity = new UserGroupsEntity();
entity.setUserGroups(populateRemainingUserGroupEntitiesContent(users));
// generate the response
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user group.
*
* @param httpServletRequest request
* @param id The id of the user group to update.
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("user-groups/{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserGroupDTO userGroupDTO = userGroupEntity.getComponent();
if (!id.equals(userGroupDTO.getId())) {
throw new IllegalArgumentException(String.format("The user group id (%s) in the request body does not equal the "
+ "user group id of the requested resource (%s).", userGroupDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userGroupEntity);
}
// Extract the revision
final Revision revision = getRevision(userGroupEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getTenantAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user group
final UserGroupEntity entity = serviceFacade.updateUserGroup(revision, userGroupDTO);
populateRemainingUserGroupEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
/**
* Removes the specified user group.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user group to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("user-groups/{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getTenantAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
},
null,
() -> {
// delete the specified user group
final UserGroupEntity entity = serviceFacade.deleteUserGroup(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -1,381 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
@Path("/user-groups")
@Api(
value = "/user-groups",
description = "Endpoint for managing user groups."
)
public class UserGroupsResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public UserGroupsResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified user group.
*
* @param userGroupEntity userGroupEntity
* @return userGroupEntity
*/
public UserGroupEntity populateRemainingUserGroupEntityContent(UserGroupEntity userGroupEntity) {
if (userGroupEntity.getComponent() != null) {
populateRemainingUserGroupContent(userGroupEntity.getComponent());
}
return userGroupEntity;
}
/**
* Populates the uri for the specified userGroup.
*/
public UserGroupDTO populateRemainingUserGroupContent(UserGroupDTO userGroup) {
// populate the user group href
userGroup.setUri(generateResourceUri("user-groups", userGroup.getId()));
return userGroup;
}
/**
* Creates a new user group.
*
* @param httpServletRequest request
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getRevision() == null || (userGroupEntity.getRevision().getVersion() == null || userGroupEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Processor.");
}
if (userGroupEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User group ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userGroupEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user group id as appropriate
userGroupEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userGroupEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userGroupEntity.getComponent().getId());
// create the user group and generate the json
final UserGroupEntity entity = serviceFacade.createUserGroup(revision, userGroupEntity.getComponent());
populateRemainingUserGroupEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user group.
*
* @param id The id of the user group to retrieve
* @return An userGroupEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUserGroup(
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
});
// get the user group
final UserGroupEntity entity = serviceFacade.getUserGroup(id, true);
populateRemainingUserGroupEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user group.
*
* @param httpServletRequest request
* @param id The id of the user group to update.
* @param userGroupEntity An userGroupEntity.
* @return An userGroupEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user group configuration details.",
required = true
) final UserGroupEntity userGroupEntity) {
if (userGroupEntity == null || userGroupEntity.getComponent() == null) {
throw new IllegalArgumentException("User group details must be specified.");
}
if (userGroupEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserGroupDTO userGroupDTO = userGroupEntity.getComponent();
if (!id.equals(userGroupDTO.getId())) {
throw new IllegalArgumentException(String.format("The user group id (%s) in the request body does not equal the "
+ "user group id of the requested resource (%s).", userGroupDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userGroupEntity);
}
// Extract the revision
final Revision revision = getRevision(userGroupEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user group
final UserGroupEntity entity = serviceFacade.updateUserGroup(revision, userGroupDTO);
populateRemainingUserGroupEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
/**
* Removes the specified user group.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user group to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user group",
response = UserGroupEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUserGroup(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user group id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable userGroups = lookup.getUserGroupsAuthorizable();
userGroups.authorize(authorizer, RequestAction.READ);
},
() -> {
},
() -> {
// delete the specified user group
final UserGroupEntity entity = serviceFacade.deleteUserGroup(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -1,381 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.web.api;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
@Path("/users")
@Api(
value = "/users",
description = "Endpoint for managing users."
)
public class UsersResource extends ApplicationResource {
private final NiFiServiceFacade serviceFacade;
private final Authorizer authorizer;
public UsersResource(NiFiServiceFacade serviceFacade, Authorizer authorizer, NiFiProperties properties, RequestReplicator requestReplicator, ClusterCoordinator clusterCoordinator) {
this.serviceFacade = serviceFacade;
this.authorizer = authorizer;
setProperties(properties);
setRequestReplicator(requestReplicator);
setClusterCoordinator(clusterCoordinator);
}
/**
* Populates the uri for the specified user.
*
* @param userEntity userEntity
* @return userEntity
*/
public UserEntity populateRemainingUserEntityContent(UserEntity userEntity) {
if (userEntity.getComponent() != null) {
populateRemainingUserContent(userEntity.getComponent());
}
return userEntity;
}
/**
* Populates the uri for the specified user.
*/
public UserDTO populateRemainingUserContent(UserDTO user) {
// populate the user href
user.setUri(generateResourceUri("users", user.getId()));
return user;
}
/**
* Creates a new user.
*
* @param httpServletRequest request
* @param userEntity An userEntity.
* @return An userEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Creates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getRevision() == null || (userEntity.getRevision().getVersion() == null || userEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Processor.");
}
if (userEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("User ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, userEntity);
}
// handle expects request (usually from the cluster manager)
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
});
}
if (validationPhase) {
return generateContinueResponse().build();
}
// set the user id as appropriate
userEntity.getComponent().setId(generateUuid());
// get revision from the config
final RevisionDTO revisionDTO = userEntity.getRevision();
Revision revision = new Revision(revisionDTO.getVersion(), revisionDTO.getClientId(), userEntity.getComponent().getId());
// create the user and generate the json
final UserEntity entity = serviceFacade.createUser(revision, userEntity.getComponent());
populateRemainingUserEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
}
/**
* Retrieves the specified user.
*
* @param id The id of the user to retrieve
* @return An userEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getUser(
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.READ);
});
// get the user
final UserEntity entity = serviceFacade.getUser(id, true);
populateRemainingUserEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Updates a user.
*
* @param httpServletRequest request
* @param id The id of the user to update.
* @param userEntity An userEntity.
* @return An userEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Updates a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response updateUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id,
@ApiParam(
value = "The user configuration details.",
required = true
) final UserEntity userEntity) {
if (userEntity == null || userEntity.getComponent() == null) {
throw new IllegalArgumentException("User details must be specified.");
}
if (userEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
// ensure the ids are the same
final UserDTO userDTO = userEntity.getComponent();
if (!id.equals(userDTO.getId())) {
throw new IllegalArgumentException(String.format("The user id (%s) in the request body does not equal the "
+ "user id of the requested resource (%s).", userDTO.getId(), id));
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, userEntity);
}
// Extract the revision
final Revision revision = getRevision(userEntity, id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.WRITE);
},
null,
() -> {
// update the user
final UserEntity entity = serviceFacade.updateUser(revision, userDTO);
populateRemainingUserEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
/**
* Removes the specified user.
*
* @param httpServletRequest request
* @param version The revision is used to verify the client is working with
* the latest version of the flow.
* @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is
* included in the response.
* @param id The id of the user to remove.
* @return A entity containing the client id and an updated revision.
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("{id}")
// TODO - @PreAuthorize("hasRole('ROLE_DFM')")
@ApiOperation(
value = "Deletes a user",
response = UserEntity.class,
authorizations = {
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeUser(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
required = false
)
@QueryParam(VERSION) final LongParameter version,
@ApiParam(
value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
required = false
)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam(
value = "The user id.",
required = true
)
@PathParam("id") final String id) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
}
// handle expects request (usually from the cluster manager)
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
revision,
lookup -> {
final Authorizable users = lookup.getUsersAuthorizable();
users.authorize(authorizer, RequestAction.READ);
},
() -> {
},
() -> {
// delete the specified user
final UserEntity entity = serviceFacade.deleteUser(revision, id);
return clusterContext(generateOkResponse(entity)).build();
}
);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.web.api.config;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
/**
* Maps authorization access exceptions into client responses.
*/
@Provider
public class AuthorizationAccessExceptionMapper implements ExceptionMapper<AuthorizationAccessException> {
private static final Logger logger = LoggerFactory.getLogger(AdministrationExceptionMapper.class);
@Override
public Response toResponse(AuthorizationAccessException e) {
// log the error
logger.error(String.format("%s. Returning %s response.", e, Response.Status.INTERNAL_SERVER_ERROR), e);
// generate the response
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).type("text/plain").build();
}
}

View File

@ -698,7 +698,7 @@ public final class DtoFactory {
final UserDTO dto = new UserDTO();
dto.setId(user.getIdentifier());
dto.setGroups(groups);
dto.setUserGroups(groups);
dto.setIdentity(user.getIdentity());
return dto;

View File

@ -19,6 +19,8 @@ package org.apache.nifi.web.dao;
import org.apache.nifi.authorization.User;
import org.apache.nifi.web.api.dto.UserDTO;
import java.util.Set;
public interface UserDAO {
/**
@ -43,6 +45,13 @@ public interface UserDAO {
*/
User getUser(String userId);
/**
* Gets all users.
*
* @return The user transfer objects
*/
Set<User> getUsers();
/**
* Updates the specified user.
*

View File

@ -19,6 +19,8 @@ package org.apache.nifi.web.dao;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import java.util.Set;
public interface UserGroupDAO {
/**
@ -43,6 +45,13 @@ public interface UserGroupDAO {
*/
Group getUserGroup(String userGroupId);
/**
* Gets all user groups.
*
* @return The user group transfer objects
*/
Set<Group> getUserGroups();
/**
* Updates the specified user group.
*

View File

@ -28,10 +28,13 @@ import org.apache.nifi.authorization.UsersAndAccessPolicies;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
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.ComponentEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.dao.AccessPolicyDAO;
import org.apache.nifi.web.dao.UserDAO;
import org.apache.nifi.web.dao.UserGroupDAO;
@ -41,7 +44,7 @@ import java.util.stream.Collectors;
public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGroupDAO, UserDAO {
private static final String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "authorizer is not of type AbstractPolicyBasedAuthorizer";
static final String MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER = "This NiFi is not configured to internally manage users, groups, and policies. Please contact your system administrator.";
private final AbstractPolicyBasedAuthorizer authorizer;
public StandardPolicyBasedAuthorizerDAO(final Authorizer authorizer) {
@ -156,34 +159,44 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
@Override
public AccessPolicy createAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
return authorizer.addAccessPolicy(buildAccessPolicy(accessPolicyDTO));
return authorizer.addAccessPolicy(buildAccessPolicy(accessPolicyDTO.getId(), accessPolicyDTO));
}
@Override
public AccessPolicy getAccessPolicy(final String accessPolicyId) {
return authorizer.getAccessPolicy(accessPolicyId);
final AccessPolicy accessPolicy = authorizer.getAccessPolicy(accessPolicyId);
if (accessPolicy == null) {
throw new ResourceNotFoundException(String.format("Unable to find access policy with id '%s'.", accessPolicyId));
}
return accessPolicy;
}
@Override
public AccessPolicy updateAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
return authorizer.updateAccessPolicy(buildAccessPolicy(accessPolicyDTO));
return authorizer.updateAccessPolicy(buildAccessPolicy(getAccessPolicy(accessPolicyDTO.getId()).getIdentifier(), accessPolicyDTO));
}
@Override
public AccessPolicy deleteAccessPolicy(final String accessPolicyId) {
return authorizer.deleteAccessPolicy(authorizer.getAccessPolicy(accessPolicyId));
return authorizer.deleteAccessPolicy(getAccessPolicy(accessPolicyId));
}
private AccessPolicy buildAccessPolicy(final AccessPolicyDTO accessPolicyDTO) {
private AccessPolicy buildAccessPolicy(final String identifier, final AccessPolicyDTO accessPolicyDTO) {
final Set<UserGroupEntity> userGroups = accessPolicyDTO.getUserGroups();
final Set<UserEntity> users = accessPolicyDTO.getUsers();
final AccessPolicy.Builder builder = new AccessPolicy.Builder()
.identifier(accessPolicyDTO.getId())
.addGroups(accessPolicyDTO.getUserGroups().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.addUsers(accessPolicyDTO.getUsers().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.identifier(identifier)
.resource(accessPolicyDTO.getResource());
if (accessPolicyDTO.getCanRead()) {
if (userGroups != null) {
builder.addGroups(userGroups.stream().map(ComponentEntity::getId).collect(Collectors.toSet()));
}
if (users != null) {
builder.addUsers(users.stream().map(ComponentEntity::getId).collect(Collectors.toSet()));
}
if (Boolean.TRUE == accessPolicyDTO.getCanRead()) {
builder.addAction(RequestAction.READ);
}
if (accessPolicyDTO.getCanWrite()) {
if (Boolean.TRUE == accessPolicyDTO.getCanWrite()) {
builder.addAction(RequestAction.WRITE);
}
return builder.build();
@ -196,28 +209,40 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
@Override
public Group createUserGroup(final UserGroupDTO userGroupDTO) {
return authorizer.addGroup(buildUserGroup(userGroupDTO));
return authorizer.addGroup(buildUserGroup(userGroupDTO.getId(), userGroupDTO));
}
@Override
public Group getUserGroup(final String userGroupId) {
return authorizer.getGroup(userGroupId);
final Group userGroup = authorizer.getGroup(userGroupId);
if (userGroup == null) {
throw new ResourceNotFoundException(String.format("Unable to find user group with id '%s'.", userGroupId));
}
return userGroup;
}
@Override
public Set<Group> getUserGroups() {
return authorizer.getGroups();
}
@Override
public Group updateUserGroup(final UserGroupDTO userGroupDTO) {
return authorizer.updateGroup(buildUserGroup(userGroupDTO));
return authorizer.updateGroup(buildUserGroup(getUserGroup(userGroupDTO.getId()).getIdentifier(), userGroupDTO));
}
@Override
public Group deleteUserGroup(final String userGroupId) {
return authorizer.deleteGroup(authorizer.getGroup(userGroupId));
return authorizer.deleteGroup(getUserGroup(userGroupId));
}
private Group buildUserGroup(final UserGroupDTO userGroupDTO) {
return new Group.Builder()
.addUsers(userGroupDTO.getUsers().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.identifier(userGroupDTO.getId()).name(userGroupDTO.getName()).build();
private Group buildUserGroup(final String identifier, final UserGroupDTO userGroupDTO) {
final Set<UserEntity> users = userGroupDTO.getUsers();
final Group.Builder builder = new Group.Builder().identifier(identifier).name(userGroupDTO.getName());
if (users != null) {
builder.addUsers(users.stream().map(ComponentEntity::getId).collect(Collectors.toSet()));
}
return builder.build();
}
@Override
@ -227,29 +252,40 @@ public class StandardPolicyBasedAuthorizerDAO implements AccessPolicyDAO, UserGr
@Override
public User createUser(final UserDTO userDTO) {
final User user = buildUser(userDTO);
return authorizer.addUser(user);
return authorizer.addUser(buildUser(userDTO.getId(), userDTO));
}
@Override
public User getUser(final String userId) {
return authorizer.getUser(userId);
final User user = authorizer.getUser(userId);
if (user == null) {
throw new ResourceNotFoundException(String.format("Unable to find user with id '%s'.", userId));
}
return user;
}
@Override
public Set<User> getUsers() {
return authorizer.getUsers();
}
@Override
public User updateUser(final UserDTO userDTO) {
return authorizer.updateUser(buildUser(userDTO));
return authorizer.updateUser(buildUser(getUser(userDTO.getId()).getIdentifier(), userDTO));
}
@Override
public User deleteUser(final String userId) {
return authorizer.deleteUser(authorizer.getUser(userId));
return authorizer.deleteUser(getUser(userId));
}
private User buildUser(final UserDTO userDTO) {
return new User.Builder()
.addGroups(userDTO.getGroups().stream().map(ComponentEntity::getId).collect(Collectors.toSet()))
.identifier(userDTO.getIdentity()).identity(userDTO.getIdentity()).build();
private User buildUser(final String identifier, final UserDTO userDTO) {
final Set<UserGroupEntity> 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

@ -361,14 +361,7 @@
<constructor-arg ref="clusterCoordinator"/>
<constructor-arg ref="requestReplicator" />
</bean>
<bean id="userGroupsResource" class="org.apache.nifi.web.api.UserGroupsResource" scope="singleton">
<constructor-arg ref="serviceFacade"/>
<constructor-arg ref="authorizer"/>
<constructor-arg ref="nifiProperties"/>
<constructor-arg ref="clusterCoordinator"/>
<constructor-arg ref="requestReplicator" />
</bean>
<bean id="usersResource" class="org.apache.nifi.web.api.UsersResource" scope="singleton">
<bean id="tenantsResource" class="org.apache.nifi.web.api.TenantsResource" scope="singleton">
<constructor-arg ref="serviceFacade"/>
<constructor-arg ref="authorizer"/>
<constructor-arg ref="nifiProperties"/>
@ -381,6 +374,7 @@
<!-- exception mapping -->
<bean class="org.apache.nifi.web.api.config.AccessDeniedExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.AuthorizationAccessExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.InvalidAuthenticationExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.AuthenticationCredentialsNotFoundExceptionMapper" scope="singleton"/>
<bean class="org.apache.nifi.web.api.config.AdministrationExceptionMapper" scope="singleton"/>

View File

@ -0,0 +1,561 @@
/*
* 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.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.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.UserEntity
import org.apache.nifi.web.api.entity.UserGroupEntity
import spock.lang.Specification
import spock.lang.Unroll
class StandardPolicyBasedAuthorizerDAOSpec extends Specification {
@Unroll
def "test non-policy-based authorizer #method throws IllegalStateException"() {
when:
daoMethod()
then:
def e = thrown(IllegalStateException)
assert e.message.equalsIgnoreCase(StandardPolicyBasedAuthorizerDAO.MSG_NON_ABSTRACT_POLICY_BASED_AUTHORIZER)
where:
method | daoMethod
'createAccessPolicy' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).createAccessPolicy(new AccessPolicyDTO(id: '1', resource: '/1', canRead: true)) }
'createUser' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).createUser(new UserDTO(id: '1', identity: 'a')) }
'createUserGroup' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).createUserGroup(new UserGroupDTO(id: '1', name: 'a')) }
'deleteAccessPolicy' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).deleteAccessPolicy('1') }
'deleteUser' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).deleteUser('1') }
'deleteUserGroup' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).deleteUserGroup('1') }
'getAccessPolicy' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).getAccessPolicy('1') }
'getUser' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).getUser('1') }
'getUserGroup' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).getUserGroup('1') }
'hasAccessPolicy' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).hasAccessPolicy('1') }
'hasUser' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).hasUser('1') }
'hasUserGroup' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).hasUserGroup('1') }
'updateAccessPolicy' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).updateAccessPolicy(new AccessPolicyDTO(id: '1', resource: '/1', canRead: true)) }
'updateUser' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).updateUser(new UserDTO(id: '1', identity: 'a')) }
'updateUserGroup' | { new StandardPolicyBasedAuthorizerDAO(Mock(Authorizer)).updateUserGroup(new UserGroupDTO(id: '1', name: 'a')) }
}
@Unroll
def "HasAccessPolicy: accessPolicy: #accessPolicy"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.hasAccessPolicy('policy-id-1')
then:
1 * authorizer.getAccessPolicy('policy-id-1') >> accessPolicy
0 * _
result == (accessPolicy != null)
where:
accessPolicy | _
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.addAction(RequestAction.READ).addAction(RequestAction.WRITE).build() | _
null | _
}
@Unroll
def "CreateAccessPolicy: accessPolicy=#accessPolicy"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new AccessPolicyDTO(id: 'policy-id-1', resource: '/fake/resource', canRead: true,
canWrite: true,
users: [new UserEntity(id: 'user-id-1')] as Set,
userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
def result = dao.createAccessPolicy(requestDTO)
then:
noExceptionThrown()
then:
1 * authorizer.addAccessPolicy(accessPolicy) >> accessPolicy
0 * _
result?.equals accessPolicy
where:
accessPolicy | _
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.addAction(RequestAction.READ).addAction(RequestAction.WRITE).build() | _
}
@Unroll
def "GetAccessPolicy: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.getAccessPolicy('policy-id-1')
then:
1 * authorizer.getAccessPolicy('policy-id-1') >> accessPolicy
0 * _
assert result?.equals(accessPolicy)
where:
accessPolicy | _
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.addAction(RequestAction.READ).addAction(RequestAction.WRITE).build() | _
}
@Unroll
def "GetAccessPolicy: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.getAccessPolicy('policy-id-1')
then:
1 * authorizer.getAccessPolicy('policy-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "UpdateAccessPolicy: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new AccessPolicyDTO(id: 'policy-id-1', resource: '/fake/resource', canRead: true,
canWrite: true,
users: [new UserEntity(id: 'user-id-1')] as Set,
userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
def result = dao.updateAccessPolicy(requestDTO)
then:
1 * authorizer.getAccessPolicy(requestDTO.id) >> accessPolicy
1 * authorizer.updateAccessPolicy(accessPolicy) >> accessPolicy
0 * _
result?.equals(accessPolicy)
where:
accessPolicy | _
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.addAction(RequestAction.READ).addAction(RequestAction.WRITE).build() | _
}
@Unroll
def "UpdateAccessPolicy: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new AccessPolicyDTO(id: 'policy-id-1', resource: '/fake/resource', canRead: true,
canWrite: true,
users: [new UserEntity(id: 'user-id-1')] as Set,
userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
dao.updateAccessPolicy(requestDTO)
then:
1 * authorizer.getAccessPolicy(requestDTO.id) >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "DeleteAccessPolicy: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.deleteAccessPolicy('policy-id-1')
then:
1 * authorizer.getAccessPolicy('policy-id-1') >> accessPolicy
1 * authorizer.deleteAccessPolicy(accessPolicy) >> accessPolicy
0 * _
result?.equals(accessPolicy)
where:
accessPolicy | _
new AccessPolicy.Builder().identifier('policy-id-1').resource('/fake/resource').addUser('user-id-1').addGroup('user-group-id-1')
.addAction(RequestAction.READ).addAction(RequestAction.WRITE).build() | _
}
@Unroll
def "DeleteAccessPolicy: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.deleteAccessPolicy('policy-id-1')
then:
1 * authorizer.getAccessPolicy('policy-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "HasUserGroup: userGroup=#userGroup"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.hasUserGroup('user-group-id-1')
then:
1 * authorizer.getGroup('user-group-id-1') >> userGroup
0 * _
result == (userGroup != null)
where:
userGroup | _
new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build() | _
null | _
}
@Unroll
def "CreateUserGroup: userGroup=#userGroup"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserGroupDTO(id: 'user-group-id-1', name: 'user group identity', users: [new UserEntity(id: 'user-id-1')] as Set)
when:
def result = dao.createUserGroup(requestDTO)
then:
noExceptionThrown()
then:
1 * authorizer.addGroup(userGroup) >> userGroup
0 * _
result?.equals userGroup
where:
userGroup | _
new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build() | _
}
@Unroll
def "GetUserGroup: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.getUserGroup('user-group-id-1')
then:
1 * authorizer.getGroup('user-group-id-1') >> userGroup
0 * _
result?.equals(userGroup)
where:
userGroup | _
new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build() | _
}
@Unroll
def "GetUserGroup: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.getUserGroup('user-group-id-1')
then:
1 * authorizer.getGroup('user-group-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "GetUserGroups: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.getUserGroups()
then:
1 * authorizer.getGroups() >> userGroups
0 * _
result?.equals(userGroups)
where:
userGroups | _
[new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build()] as Set | _
}
@Unroll
def "UpdateUserGroup: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserGroupDTO(id: 'user-group-id-1', name: 'user group identity', users: [new UserEntity(id: 'user-id-1')] as Set)
when:
def result = dao.updateUserGroup(requestDTO)
then:
1 * authorizer.getGroup(requestDTO.id) >> userGroup
1 * authorizer.updateGroup(userGroup) >> userGroup
0 * _
result?.equals(userGroup)
where:
userGroup | _
new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build() | _
}
@Unroll
def "UpdateUserGroup: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserGroupDTO(id: 'user-group-id-1', name: 'user group identity', users: [new UserEntity(id: 'user-id-1')] as Set)
when:
dao.updateUserGroup(requestDTO)
then:
1 * authorizer.getGroup(requestDTO.id) >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "DeleteUserGroup: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.deleteUserGroup('user-group-id-1')
then:
1 * authorizer.getGroup('user-group-id-1') >> userGroup
1 * authorizer.deleteGroup(userGroup) >> userGroup
0 * _
assert result?.equals(userGroup)
where:
userGroup | _
new Group.Builder().identifier('user-group-id-1').name('user-group-id-1').addUser('user-id-1').build() | _
}
@Unroll
def "DeleteUserGroup: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.deleteUserGroup('user-group-id-1')
then:
1 * authorizer.getGroup('user-group-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "HasUser: user=#user"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.hasUser('user-id-1')
then:
1 * authorizer.getUser('user-id-1') >> user
0 * _
result == (user != null)
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
}
@Unroll
def "CreateUser: user=#user"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserDTO(id: 'user-id-1', identity: 'user identity', userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
def result = dao.createUser(requestDTO)
then:
noExceptionThrown()
then:
1 * authorizer.addUser(user) >> user
0 * _
result?.equals user
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
}
@Unroll
def "GetUser: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.getUser('user-id-1')
then:
1 * authorizer.getUser('user-id-1') >> user
result?.equals(user)
0 * _
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
}
@Unroll
def "GetUser: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.getUser('user-id-1')
then:
1 * authorizer.getUser('user-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "GetUsers: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.getUsers()
then:
1 * authorizer.getUsers() >> users
result?.containsAll(users)
0 * _
where:
users | _
[new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build()] as Set | _
}
@Unroll
def "UpdateUser: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserDTO(id: 'user-id-1', identity: 'user identity', userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
def result = dao.updateUser(requestDTO)
then:
1 * authorizer.getUser(requestDTO.id) >> user
1 * authorizer.updateUser(user) >> user
0 * _
result?.equals(user)
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
}
@Unroll
def "UpdateUser: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
def requestDTO = new UserDTO(id: 'user-id-1', identity: 'user identity', userGroups: [new UserGroupEntity(id: 'user-group-id-1')] as Set)
when:
dao.updateUser(requestDTO)
then:
1 * authorizer.getUser(requestDTO.id) >> null
0 * _
thrown ResourceNotFoundException
}
@Unroll
def "DeleteUser: success"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
def result = dao.deleteUser('user-id-1')
then:
1 * authorizer.getUser('user-id-1') >> user
1 * authorizer.deleteUser(user) >> user
0 * _
result?.equals(user)
where:
user | _
new User.Builder().identifier('user-id-1').identity('user identity').addGroup('user-group-id-1').build() | _
}
@Unroll
def "DeleteUser: failure"() {
given:
def authorizer = Mock AbstractPolicyBasedAuthorizer
def dao = new StandardPolicyBasedAuthorizerDAO(authorizer)
when:
dao.deleteUser('user-id-1')
then:
1 * authorizer.getUser('user-id-1') >> null
0 * _
thrown ResourceNotFoundException
}
}