[ 
https://issues.apache.org/jira/browse/NIFI-1952?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15329477#comment-15329477
 ] 

ASF GitHub Bot commented on NIFI-1952:
--------------------------------------

Github user jtstorck commented on a diff in the pull request:

    https://github.com/apache/nifi/pull/526#discussion_r66966751
  
    --- Diff: 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/UsersResource.java
 ---
    @@ -0,0 +1,373 @@
    +/*
    + * 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.web.NiFiServiceFacade;
    +import org.apache.nifi.web.Revision;
    +import org.apache.nifi.web.UpdateResult;
    +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 {
    +
    +    final private NiFiServiceFacade serviceFacade;
    +    final private Authorizer authorizer;
    +
    +    public UsersResource(NiFiServiceFacade serviceFacade, Authorizer 
authorizer) {
    +        this.serviceFacade = serviceFacade;
    +        this.authorizer = authorizer;
    +    }
    +
    +    /**
    +     * 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.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());
    +
    +        // create the user and generate the json
    +        final UserEntity entity = 
serviceFacade.createUser(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);
    +        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 UpdateResult<UserEntity> updateResult = 
serviceFacade.updateUser(revision, userDTO);
    +
    +                    // get the results
    +                    final UserEntity entity = updateResult.getResult();
    +                    populateRemainingUserEntityContent(entity);
    +
    +                    if (updateResult.isNew()) {
    +                        return 
clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()),
 entity)).build();
    +                    } else {
    +                        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);
    +                },
    +                () -> {},
    --- End diff --
    
    I will update with null.


> Create REST endpoints for user/group/policy management
> ------------------------------------------------------
>
>                 Key: NIFI-1952
>                 URL: https://issues.apache.org/jira/browse/NIFI-1952
>             Project: Apache NiFi
>          Issue Type: Sub-task
>          Components: Core Framework
>    Affects Versions: 1.0.0
>            Reporter: Jeff Storck
>            Assignee: Jeff Storck
>             Fix For: 1.0.0
>
>
> REST endpoints are needed to provide CRUD capability for mutable authorizers 
> (extensions of AbstractPolicyBasedAuthorizer) to manage users, groups, and 
> policies.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to