Repository: nifi Updated Branches: refs/heads/master b911c9dbd -> 64719b6f9
http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UserGroupsResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UserGroupsResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UserGroupsResource.java deleted file mode 100644 index a770e8b..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UserGroupsResource.java +++ /dev/null @@ -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(); - } - ); - } -} http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UsersResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UsersResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UsersResource.java deleted file mode 100644 index 4a7bc4b..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UsersResource.java +++ /dev/null @@ -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(); - } - ); - } -} http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AuthorizationAccessExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AuthorizationAccessExceptionMapper.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AuthorizationAccessExceptionMapper.java new file mode 100644 index 0000000..c1482e7 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AuthorizationAccessExceptionMapper.java @@ -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(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java index 0577b03..0bd275a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java @@ -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; http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserDAO.java index a6d4bb4..8d337f8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserDAO.java @@ -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 { /** @@ -44,6 +46,13 @@ public interface UserDAO { User getUser(String userId); /** + * Gets all users. + * + * @return The user transfer objects + */ + Set<User> getUsers(); + + /** * Updates the specified user. * * @param userDTO The user DTO http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java index 878d16f..0e48584 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/UserGroupDAO.java @@ -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 { /** @@ -44,6 +46,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. * * @param userGroupDTO The user group DTO http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java index 25cc5ac..ff5f20e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAO.java @@ -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(); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml index 6eb9a3a..8faedfb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml @@ -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"/> http://git-wip-us.apache.org/repos/asf/nifi/blob/64719b6f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAOSpec.groovy ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAOSpec.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAOSpec.groovy new file mode 100644 index 0000000..bfffd26 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/groovy/org/apache/nifi/web/dao/impl/StandardPolicyBasedAuthorizerDAOSpec.groovy @@ -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 + } +}
