http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java index 97ad0c1..b7a0217 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/FlowResource.java @@ -21,10 +21,9 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; -import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.Authorizer; import org.apache.nifi.registry.flow.VersionedFlow; -import org.apache.nifi.registry.flow.VersionedFlowSnapshot; -import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; +import org.apache.nifi.registry.service.AuthorizationService; import org.apache.nifi.registry.service.RegistryService; import org.apache.nifi.registry.service.params.QueryParameters; import org.apache.nifi.registry.service.params.SortParameter; @@ -36,22 +35,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; -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 javax.ws.rs.core.UriInfo; +import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.SortedSet; @Component @Path("/flows") @@ -59,7 +53,7 @@ import java.util.SortedSet; value = "/flows", description = "Create named flows that can be versioned. Search for and retrieve existing flows." ) -public class FlowResource { +public class FlowResource extends AuthorizableApplicationResource { private static final Logger logger = LoggerFactory.getLogger(FlowResource.class); @@ -71,7 +65,12 @@ public class FlowResource { private final RegistryService registryService; @Autowired - public FlowResource(final RegistryService registryService, final LinkService linkService) { + public FlowResource( + final RegistryService registryService, + final LinkService linkService, + final AuthorizationService authorizationService, + final Authorizer authorizer) { + super(authorizer, authorizationService); this.registryService = registryService; this.linkService = linkService; } @@ -85,206 +84,34 @@ public class FlowResource { response = VersionedFlow.class, responseContainer = "List" ) - public Response getFlows( + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403) }) + public Response getAuthorizedFlows( @ApiParam(value = SortParameter.API_PARAM_DESCRIPTION, format = "field:order", allowMultiple = true, example = "name:ASC") @QueryParam("sort") final List<String> sortParameters) { + Set<String> authorizedBucketIds = getAuthorizedBucketIds(); + + if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { + // not authorized for any bucket, return empty list of items + return Response.status(Response.Status.OK).entity(new ArrayList<VersionedFlow>()).build(); + } + final QueryParameters.Builder paramsBuilder = new QueryParameters.Builder(); for (String sortParam : sortParameters) { paramsBuilder.addSort(SortParameter.fromString(sortParam)); } - final List<VersionedFlow> flows = registryService.getFlows(paramsBuilder.build()); + final List<VersionedFlow> flows = registryService.getFlows(paramsBuilder.build(), authorizedBucketIds); linkService.populateFlowLinks(flows); return Response.status(Response.Status.OK).entity(flows).build(); } @GET - @Path("/{flowId}") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get metadata for an existing flow the registry has stored. If verbose is true, then the metadata " + - "about all snapshots for the flow will also be returned.", - response = VersionedFlow.class - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response getFlow(@PathParam("flowId") final String flowId, - @QueryParam("verbose") @DefaultValue("false") boolean verbose) { - - final VersionedFlow flow = registryService.getFlow(flowId, verbose); - linkService.populateFlowLinks(flow); - - if (flow.getSnapshotMetadata() != null) { - linkService.populateSnapshotLinks(flow.getSnapshotMetadata()); - } - - return Response.status(Response.Status.OK).entity(flow).build(); - } - - @PUT - @Path("/{flowId}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Update an existing flow the registry has stored.", - response = VersionedFlow.class - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response updateFlow(@PathParam("flowId") final String flowId, final VersionedFlow flow) { - if (StringUtils.isBlank(flowId)) { - throw new IllegalArgumentException("Flow Id cannot be blank"); - } - - if (flow == null) { - throw new IllegalArgumentException("Flow cannot be null"); - } - - if (flow.getIdentifier() != null && !flowId.equals(flow.getIdentifier())) { - throw new IllegalArgumentException("Flow id in path param must match flow id in body"); - } - - if (flow.getIdentifier() == null) { - flow.setIdentifier(flowId); - } - - final VersionedFlow updatedFlow = registryService.updateFlow(flow); - return Response.status(Response.Status.OK).entity(updatedFlow).build(); - } - - @DELETE - @Path("/{flowId}") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Delete an existing flow the registry has stored.", - response = VersionedFlow.class - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response deleteFlow(@PathParam("flowId") final String flowId) { - final VersionedFlow deletedFlow = registryService.deleteFlow(flowId); - return Response.status(Response.Status.OK).entity(deletedFlow).build(); - } - - @POST - @Path("/{flowId}/versions") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Create the next version of a given flow ID. " + - "The version number is created by the server and a location URI for the created version resource is returned.", - response = VersionedFlowSnapshot.class - ) - public Response createFlowVersion(@PathParam("flowId") final String flowId, final VersionedFlowSnapshot snapshot) { - if (StringUtils.isBlank(flowId)) { - throw new IllegalArgumentException("Flow Id cannot be blank"); - } - - if (snapshot == null) { - throw new IllegalArgumentException("VersionedFlowSnapshot cannot be null"); - } - - if (snapshot.getSnapshotMetadata() != null && snapshot.getSnapshotMetadata().getFlowIdentifier() != null - && !flowId.equals(snapshot.getSnapshotMetadata().getFlowIdentifier())) { - throw new IllegalArgumentException("Flow id in path param must match flow id in body"); - } - - if (snapshot.getSnapshotMetadata() != null && snapshot.getSnapshotMetadata().getFlowIdentifier() != null) { - snapshot.getSnapshotMetadata().setFlowIdentifier(flowId); - } - - final VersionedFlowSnapshot createdSnapshot = registryService.createFlowSnapshot(snapshot); - return Response.status(Response.Status.OK).entity(createdSnapshot).build(); - } - - @GET - @Path("/{flowId}/versions") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get summary of all versions of a flow for a given flow ID.", - response = VersionedFlowSnapshotMetadata.class, - responseContainer = "List" - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response getFlowVersions(@PathParam("flowId") final String flowId) { - final VersionedFlow flow = registryService.getFlow(flowId, true); - - if (flow.getSnapshotMetadata() != null) { - linkService.populateSnapshotLinks(flow.getSnapshotMetadata()); - } - - return Response.status(Response.Status.OK).entity(flow.getSnapshotMetadata()).build(); - } - - @GET - @Path("/{flowId}/versions/latest") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get the latest version of a flow for a given flow ID", - response = VersionedFlowSnapshot.class - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response getLatestFlowVersion(@PathParam("flowId") final String flowId) { - final VersionedFlow flow = registryService.getFlow(flowId, true); - - final SortedSet<VersionedFlowSnapshotMetadata> snapshots = flow.getSnapshotMetadata(); - if (snapshots == null || snapshots.size() == 0) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - - final VersionedFlowSnapshotMetadata lastSnapshotMetadata = snapshots.last(); - - final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot( - lastSnapshotMetadata.getFlowIdentifier(), lastSnapshotMetadata.getVersion()); - - return Response.status(Response.Status.OK).entity(lastSnapshot).build(); - } - - @GET - @Path("/{flowId}/versions/{versionNumber: \\d+}") - @Consumes(MediaType.WILDCARD) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get a given version of a flow for a given flow ID", - response = VersionedFlowSnapshot.class - ) - @ApiResponses( - value = { - @ApiResponse(code = 404, message = "The specified resource could not be found."), - } - ) - public Response getFlowVersion( - @PathParam("flowId") final String flowId, - @PathParam("versionNumber") final Integer versionNumber) { - final VersionedFlowSnapshot snapshot = registryService.getFlowSnapshot(flowId, versionNumber); - return Response.status(Response.Status.OK).entity(snapshot).build(); - } - - @GET @Path("fields") @Consumes(MediaType.WILDCARD) @Produces(MediaType.APPLICATION_JSON)
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/HttpStatusMessages.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/HttpStatusMessages.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/HttpStatusMessages.java new file mode 100644 index 0000000..a3ba939 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/HttpStatusMessages.java @@ -0,0 +1,30 @@ +/* + * 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.registry.web.api; + +class HttpStatusMessages { + + /* 4xx messages */ + static final String MESSAGE_400 = "NiFi Registry was unable to complete the request because it was invalid. The request should not be retried without modification."; + static final String MESSAGE_401 = "Client could not be authenticated."; + static final String MESSAGE_403 = "Client is not authorized to make this request."; + static final String MESSAGE_404 = "The specified resource could not be found."; + static final String MESSAGE_409 = "NiFi Registry was unable to complete the request because it assumes a server state that is not valid."; + + /* 5xx messages */ + static final String MESSAGE_500 = "NiFi Registry was unable to complete the request because an unexpected error occurred."; +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java index cb99a1d..c6df1bf 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java @@ -19,7 +19,10 @@ package org.apache.nifi.registry.web.api; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import org.apache.nifi.registry.authorization.Authorizer; +import org.apache.nifi.registry.authorization.RequestAction; import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.service.AuthorizationService; import org.apache.nifi.registry.service.RegistryService; import org.apache.nifi.registry.service.params.QueryParameters; import org.apache.nifi.registry.service.params.SortParameter; @@ -40,6 +43,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -49,7 +53,7 @@ import java.util.Set; value = "/items", description = "Retrieve items across all buckets for which the user is authorized." ) -public class ItemResource { +public class ItemResource extends AuthorizableApplicationResource { private static final Logger LOGGER = LoggerFactory.getLogger(ItemResource.class); @@ -57,11 +61,15 @@ public class ItemResource { UriInfo uriInfo; private final LinkService linkService; - private final RegistryService registryService; @Autowired - public ItemResource(final RegistryService registryService, final LinkService linkService) { + public ItemResource( + final RegistryService registryService, + final LinkService linkService, + final AuthorizationService authorizationService, + final Authorizer authorizer) { + super(authorizer, authorizationService); this.registryService = registryService; this.linkService = linkService; } @@ -80,12 +88,19 @@ public class ItemResource { @QueryParam("sort") final List<String> sortParameters) { + Set<String> authorizedBucketIds = getAuthorizedBucketIds(); + + if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) { + // not authorized for any bucket, return empty list of items + return Response.status(Response.Status.OK).entity(new ArrayList<BucketItem>()).build(); + } + final QueryParameters.Builder paramsBuilder = new QueryParameters.Builder(); for (String sortParam : sortParameters) { paramsBuilder.addSort(SortParameter.fromString(sortParam)); } - final List<BucketItem> items = registryService.getBucketItems(paramsBuilder.build()); + final List<BucketItem> items = registryService.getBucketItems(paramsBuilder.build(), authorizedBucketIds); linkService.populateItemLinks(items); return Response.status(Response.Status.OK).entity(items).build(); @@ -108,6 +123,7 @@ public class ItemResource { @QueryParam("sort") final List<String> sortParameters) { + authorizeBucketAccess(RequestAction.READ, bucketId); final QueryParameters.Builder paramsBuilder = new QueryParameters.Builder(); for (String sortParam : sortParameters) { paramsBuilder.addSort(SortParameter.fromString(sortParam)); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java new file mode 100644 index 0000000..bcef565 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java @@ -0,0 +1,91 @@ +/* + * 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.registry.web.api; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.nifi.registry.authorization.Authorizer; +import org.apache.nifi.registry.authorization.RequestAction; +import org.apache.nifi.registry.authorization.resource.Authorizable; +import org.apache.nifi.registry.authorization.user.NiFiUserUtils; +import org.apache.nifi.registry.service.AuthorizationService; +import org.apache.nifi.registry.model.authorization.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * RESTful endpoint for retrieving system diagnostics. + */ +@Component +@Path("/resources") +@Api( + value = "/resources", + description = "Provides the resources in this NiFi that can have access/authorization policies." +) +public class ResourceResource extends AuthorizableApplicationResource { + + private static final Logger logger = LoggerFactory.getLogger(ResourceResource.class); + + @Autowired + public ResourceResource(AuthorizationService authorizationService, Authorizer authorizer) { + super(authorizer, authorizationService); + } + + private void authorizeResource() { + authorizationService.authorizeAccess(lookup -> { + final Authorizable resource = lookup.getResourcesAuthorizable(); + resource.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()); + }); + } + + /** + * Gets the available resources that support access/authorization policies. + * + * @return A resourcesEntity. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + value = "Gets the available resources that support access/authorization policies", + response = Resource.class, + responseContainer = "List" + ) + @ApiResponses({ + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403) }) + public Response getResources() { + authorizeResource(); + + final List<Resource> resources = authorizationService.getResources(); + + return generateOkResponse(resources).build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java new file mode 100644 index 0000000..6b02938 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java @@ -0,0 +1,486 @@ +/* + * 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.registry.web.api; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.Authorizer; +import org.apache.nifi.registry.authorization.AuthorizerCapabilityDetection; +import org.apache.nifi.registry.authorization.RequestAction; +import org.apache.nifi.registry.authorization.resource.Authorizable; +import org.apache.nifi.registry.authorization.user.NiFiUserUtils; +import org.apache.nifi.registry.model.authorization.User; +import org.apache.nifi.registry.model.authorization.UserGroup; +import org.apache.nifi.registry.service.AuthorizationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +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.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.List; + +/** + * RESTful endpoints for managing tenants, ie, users and user groups. + */ +@Component +@Path("tenants") +@Api( + value = "tenants", + description = "Endpoint for managing users and user groups." +) +public class TenantResource extends AuthorizableApplicationResource { + + private static final Logger logger = LoggerFactory.getLogger(TenantResource.class); + + @Autowired + public TenantResource( + Authorizer authorizer, + AuthorizationService authorizationService) { + super(authorizer, authorizationService); + } + + + // ---------- User endpoints -------------------------------------------------------------------------------------- + + /** + * Creates a new user. + * + * @param httpServletRequest request + * @param requestUser the user to create + * @return the user that was created + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("users") + @ApiOperation( + value = "Creates a user", + notes = NON_GUARANTEED_ENDPOINT, + response = User.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response createUser( + @Context final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user configuration details.", required = true) + final User requestUser) { + + verifyAuthorizerSupportsConfigurableUserGroups(); + + if (requestUser == null) { + throw new IllegalArgumentException("User details must be specified when creating a new user."); + } + if (requestUser.getIdentifier() != null) { + throw new IllegalArgumentException("User identifier cannot be specified when creating a new user."); + } + if (StringUtils.isBlank(requestUser.getIdentity())) { + throw new IllegalArgumentException("User identity must be specified when creating a new user."); + } + + authorizeAccess(RequestAction.WRITE); + + User createdUser = authorizationService.createUser(requestUser); + + String locationUri = generateUserUri(createdUser); + return generateCreatedResponse(URI.create(locationUri), createdUser).build(); + } + + /** + * Retrieves all the of users in this NiFi. + * + * @return a list of users + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("users") + @ApiOperation( + value = "Gets all users", + notes = NON_GUARANTEED_ENDPOINT, + response = User.class, + responseContainer = "List" + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getUsers() { + verifyAuthorizerIsManaged(); + + authorizeAccess(RequestAction.READ); + + // get all the users + final List<User> users = authorizationService.getUsers(); + + // generate the response + return generateOkResponse(users).build(); + } + + /** + * Retrieves the specified user. + * + * @param identifier The id of the user to retrieve + * @return An userEntity. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("users/{id}") + @ApiOperation( + value = "Gets a user", + notes = NON_GUARANTEED_ENDPOINT, + response = User.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getUser( + @ApiParam(value = "The user id.", required = true) + @PathParam("id") final String identifier) { + verifyAuthorizerIsManaged(); + authorizeAccess(RequestAction.READ); + + final User user = authorizationService.getUser(identifier); + return generateOkResponse(user).build(); + } + + /** + * Updates a user. + * + * @param httpServletRequest request + * @param identifier The id of the user to update + * @param requestUser The user with updated fields. + * @return The updated user + */ + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("users/{id}") + @ApiOperation( + value = "Updates a user", + notes = NON_GUARANTEED_ENDPOINT, + response = User.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response updateUser( + @Context final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user id.", required = true) + @PathParam("id") final String identifier, + @ApiParam(value = "The user configuration details.", required = true) + final User requestUser) { + + verifyAuthorizerSupportsConfigurableUserGroups(); + + if (requestUser == null) { + throw new IllegalArgumentException("User details must be specified when updating a user."); + } + if (!identifier.equals(requestUser.getIdentifier())) { + throw new IllegalArgumentException(String.format("The user id in the request body (%s) does not equal the " + + "user id of the requested resource (%s).", requestUser.getIdentifier(), identifier)); + } + + authorizeAccess(RequestAction.WRITE); + + final User updatedUser = authorizationService.updateUser(requestUser); + return generateOkResponse(updatedUser).build(); + } + + /** + * Removes the specified user. + * + * @param httpServletRequest request + * @param identifier 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}") + @ApiOperation( + value = "Deletes a user", + notes = NON_GUARANTEED_ENDPOINT, + response = User.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response removeUser( + @Context final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user id.", required = true) + @PathParam("id") final String identifier) { + + verifyAuthorizerSupportsConfigurableUserGroups(); + authorizeAccess(RequestAction.WRITE); + + final User user = authorizationService.deleteUser(identifier); + return generateOkResponse(user).build(); + } + + + // ---------- User Group endpoints -------------------------------------------------------------------------------- + + /** + * Creates a new user group. + * + * @param httpServletRequest request + * @param requestUserGroup the user group to create + * @return the created user group + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("user-groups") + @ApiOperation( + value = "Creates a user group", + notes = NON_GUARANTEED_ENDPOINT, + response = UserGroup.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response createUserGroup( + @Context final HttpServletRequest httpServletRequest, + @ApiParam( + value = "The user group configuration details.", + required = true + ) final UserGroup requestUserGroup) { + + verifyAuthorizerSupportsConfigurableUserGroups(); + + if (requestUserGroup == null) { + throw new IllegalArgumentException("User group details must be specified when creating a new group."); + } + if (requestUserGroup.getIdentifier() != null) { + throw new IllegalArgumentException("User group ID cannot be specified when creating a new group."); + } + if (StringUtils.isBlank(requestUserGroup.getIdentity())) { + throw new IllegalArgumentException("User group identity must be specified when creating a new group."); + } + + authorizeAccess(RequestAction.WRITE); + + UserGroup createdGroup = authorizationService.createUserGroup(requestUserGroup); + String locationUri = generateUserGroupUri(createdGroup); + + return generateCreatedResponse(URI.create(locationUri), createdGroup).build(); + } + + /** + * Retrieves all the of user groups in this NiFi. + * + * @return a list of all user groups in this NiFi. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("user-groups") + @ApiOperation( + value = "Gets all user groups", + notes = NON_GUARANTEED_ENDPOINT, + response = UserGroup.class, + responseContainer = "List" + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getUserGroups() { + verifyAuthorizerIsManaged(); + authorizeAccess(RequestAction.READ); + + final List<UserGroup> userGroups = authorizationService.getUserGroups(); + return generateOkResponse(userGroups).build(); + } + + /** + * Retrieves the specified user group. + * + * @param identifier The id of the user group to retrieve + * @return An userGroupEntity. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("user-groups/{id}") + @ApiOperation( + value = "Gets a user group", + notes = NON_GUARANTEED_ENDPOINT, + response = UserGroup.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response getUserGroup( + @ApiParam(value = "The user group id.", required = true) + @PathParam("id") final String identifier) { + verifyAuthorizerIsManaged(); + authorizeAccess(RequestAction.READ); + + final UserGroup userGroup = authorizationService.getUserGroup(identifier); + return generateOkResponse(userGroup).build(); + } + + /** + * Updates a user group. + * + * @param httpServletRequest request + * @param identifier The id of the user group to update. + * @param requestUserGroup The user group with updated fields. + * @return The resulting, updated user group. + */ + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("user-groups/{id}") + @ApiOperation( + value = "Updates a user group", + notes = NON_GUARANTEED_ENDPOINT, + response = UserGroup.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response updateUserGroup( + @Context final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user group id.", required = true) + @PathParam("id") final String identifier, + @ApiParam(value = "The user group configuration details.", required = true) + final UserGroup requestUserGroup) { + + verifyAuthorizerSupportsConfigurableUserGroups(); + + if (requestUserGroup == null) { + throw new IllegalArgumentException("User group details must be specified to update a user group."); + } + if (!identifier.equals(requestUserGroup.getIdentifier())) { + throw new IllegalArgumentException(String.format("The user group id in the request body (%s) does not equal the " + + "user group id of the requested resource (%s).", requestUserGroup.getIdentifier(), identifier)); + } + + authorizeAccess(RequestAction.WRITE); + + UserGroup updatedUserGroup = authorizationService.updateUserGroup(requestUserGroup); + return generateOkResponse(updatedUserGroup).build(); + } + + /** + * Removes the specified user group. + * + * @param httpServletRequest request + * @param identifier The id of the user group to remove. + * @return The deleted user group. + */ + @DELETE + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("user-groups/{id}") + @ApiOperation( + value = "Deletes a user group", + notes = NON_GUARANTEED_ENDPOINT, + response = UserGroup.class + ) + @ApiResponses({ + @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), + @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), + @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), + @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), + @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) + public Response removeUserGroup( + @Context final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user group id.", required = true) + @PathParam("id") + final String identifier) { + verifyAuthorizerSupportsConfigurableUserGroups(); + authorizeAccess(RequestAction.WRITE); + + final UserGroup userGroup = authorizationService.deleteUserGroup(identifier); + return generateOkResponse(userGroup).build(); + } + + + private void verifyAuthorizerIsManaged() { + if (!AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer)) { + throw new IllegalStateException(AuthorizationService.MSG_NON_MANAGED_AUTHORIZER); + } + } + + private void verifyAuthorizerSupportsConfigurableUserGroups() { + if (!AuthorizerCapabilityDetection.isConfigurableUserGroupProvider(authorizer)) { + throw new IllegalStateException(AuthorizationService.MSG_NON_CONFIGURABLE_USERS); + } + } + + private void authorizeAccess(RequestAction actionType) { + authorizationService.authorizeAccess(lookup -> { + final Authorizable tenantsAuthorizable = lookup.getTenantsAuthorizable(); + tenantsAuthorizable.authorize(authorizer, actionType, NiFiUserUtils.getNiFiUser()); + }); + } + + private String generateUserUri(final User user) { + return generateResourceUri("tenants", "users", user.getIdentifier()); + } + + private String generateUserGroupUri(final UserGroup userGroup) { + return generateResourceUri("tenants", "user-groups", userGroup.getIdentifier()); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java index e18d583..38d3d0e 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowLinkBuilder.java @@ -27,7 +27,7 @@ import java.net.URI; */ public class VersionedFlowLinkBuilder implements LinkBuilder<VersionedFlow> { - private static final String PATH = "flows/{id}"; + private static final String PATH = "buckets/{bucketId}/flows/{flowId}"; @Override public Link createLink(final VersionedFlow versionedFlow) { @@ -36,7 +36,8 @@ public class VersionedFlowLinkBuilder implements LinkBuilder<VersionedFlow> { } final URI uri = UriBuilder.fromPath(PATH) - .resolveTemplate("id", versionedFlow.getIdentifier()) + .resolveTemplate("bucketId", versionedFlow.getBucketIdentifier()) + .resolveTemplate("flowId", versionedFlow.getIdentifier()) .build(); return Link.fromUri(uri).rel("self").build(); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java index 47eb15f..4085c6d 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/link/builder/VersionedFlowSnapshotLinkBuilder.java @@ -27,7 +27,7 @@ import java.net.URI; */ public class VersionedFlowSnapshotLinkBuilder implements LinkBuilder<VersionedFlowSnapshotMetadata> { - private static final String PATH = "flows/{flowId}/versions/{versionNumber}"; + private static final String PATH = "buckets/{bucketId}/flows/{flowId}/versions/{versionNumber}"; @Override public Link createLink(final VersionedFlowSnapshotMetadata snapshotMetadata) { @@ -36,6 +36,7 @@ public class VersionedFlowSnapshotLinkBuilder implements LinkBuilder<VersionedFl } final URI uri = UriBuilder.fromPath(PATH) + .resolveTemplate("bucketId", snapshotMetadata.getBucketIdentifier()) .resolveTemplate("flowId", snapshotMetadata.getFlowIdentifier()) .resolveTemplate("versionNumber", snapshotMetadata.getVersion()) .build(); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AccessDeniedExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AccessDeniedExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AccessDeniedExceptionMapper.java new file mode 100644 index 0000000..68acb77 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AccessDeniedExceptionMapper.java @@ -0,0 +1,73 @@ +/* + * 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.registry.web.mapper; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.exception.AccessDeniedException; +import org.apache.nifi.registry.authorization.user.NiFiUser; +import org.apache.nifi.registry.authorization.user.NiFiUserUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * Maps access denied exceptions into a client response. + */ +@Provider +public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDeniedException> { + + private static final Logger logger = LoggerFactory.getLogger(AccessDeniedExceptionMapper.class); + + @Override + public Response toResponse(AccessDeniedException exception) { + // get the current user + NiFiUser user = NiFiUserUtils.getNiFiUser(); + + // if the user was authenticated - forbidden, otherwise unauthorized... the user may be null if the + // AccessDeniedException was thrown from a /access endpoint that isn't subject to the security + // filter chain. for instance, one that performs kerberos negotiation + final Status status; + if (user == null || user.isAnonymous()) { + status = Status.UNAUTHORIZED; + } else { + status = Status.FORBIDDEN; + } + + final String identity; + if (user == null) { + identity = "<no user found>"; + } else { + identity = user.toString(); + } + + logger.info(String.format("%s does not have permission to access the requested resource. %s Returning %s response.", identity, exception.getMessage(), status)); + + if (logger.isDebugEnabled()) { + logger.debug(StringUtils.EMPTY, exception); + } + + return Response.status(status) + .entity(String.format("%s Contact the system administrator.", exception.getMessage())) + .type("text/plain") + .build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AdministrationExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AdministrationExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AdministrationExceptionMapper.java new file mode 100644 index 0000000..69f7862 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AdministrationExceptionMapper.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.registry.web.mapper; + +import org.apache.nifi.registry.exception.AdministrationException; +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 administration exceptions into client responses. + */ +@Provider +public class AdministrationExceptionMapper implements ExceptionMapper<AdministrationException> { + + private static final Logger logger = LoggerFactory.getLogger(AdministrationExceptionMapper.class); + + @Override + public Response toResponse(AdministrationException exception) { + // log the error + logger.error(String.format("%s. Returning %s response.", exception, Response.Status.INTERNAL_SERVER_ERROR), exception); + + // generate the response + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(exception.getMessage()).type("text/plain").build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthenticationCredentialsNotFoundExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthenticationCredentialsNotFoundExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthenticationCredentialsNotFoundExceptionMapper.java new file mode 100644 index 0000000..a94b462 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthenticationCredentialsNotFoundExceptionMapper.java @@ -0,0 +1,48 @@ +/* + * 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.registry.web.mapper; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * Maps exceptions that occur because no valid credentials were found into the corresponding response. + */ +@Provider +public class AuthenticationCredentialsNotFoundExceptionMapper implements ExceptionMapper<AuthenticationCredentialsNotFoundException> { + + private static final Logger logger = LoggerFactory.getLogger(AuthenticationCredentialsNotFoundExceptionMapper.class); + + @Override + public Response toResponse(AuthenticationCredentialsNotFoundException exception) { + // log the error + logger.info(String.format("No valid credentials were found in the request: %s. Returning %s response.", exception, Response.Status.FORBIDDEN)); + + if (logger.isDebugEnabled()) { + logger.debug(StringUtils.EMPTY, exception); + } + + return Response.status(Response.Status.FORBIDDEN).entity("Access is denied.").type("text/plain").build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthorizationAccessExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthorizationAccessExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/AuthorizationAccessExceptionMapper.java new file mode 100644 index 0000000..4148cf5 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/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.registry.web.mapper; + +import org.apache.nifi.registry.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(AuthorizationAccessExceptionMapper.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-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/InvalidAuthenticationExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/InvalidAuthenticationExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/InvalidAuthenticationExceptionMapper.java new file mode 100644 index 0000000..1216a0c --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/InvalidAuthenticationExceptionMapper.java @@ -0,0 +1,45 @@ +/* + * 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.registry.web.mapper; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.web.security.InvalidAuthenticationException; +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 access denied exceptions into a client response. + */ +@Provider +public class InvalidAuthenticationExceptionMapper implements ExceptionMapper<InvalidAuthenticationException> { + + private static final Logger logger = LoggerFactory.getLogger(InvalidAuthenticationExceptionMapper.class); + + @Override + public Response toResponse(InvalidAuthenticationException exception) { + if (logger.isDebugEnabled()) { + logger.debug(StringUtils.EMPTY, exception); + } + + return Response.status(Response.Status.UNAUTHORIZED).entity(exception.getMessage()).type("text/plain").build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NotFoundExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NotFoundExceptionMapper.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NotFoundExceptionMapper.java new file mode 100644 index 0000000..0a6797d --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NotFoundExceptionMapper.java @@ -0,0 +1,48 @@ +/* + * 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.registry.web.mapper; + +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Maps not found exceptions into client responses. + */ +@Provider +public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> { + + private static final Logger logger = LoggerFactory.getLogger(NotFoundExceptionMapper.class); + + @Override + public Response toResponse(NotFoundException exception) { + // log the error + logger.info(String.format("%s. Returning %s response.", exception, Response.Status.NOT_FOUND)); + + if (logger.isDebugEnabled()) { + logger.debug(StringUtils.EMPTY, exception); + } + + return Response.status(Response.Status.NOT_FOUND).entity(exception.getMessage()).type("text/plain").build(); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/response/AuthenticationResponse.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/response/AuthenticationResponse.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/response/AuthenticationResponse.java new file mode 100644 index 0000000..a0b87b5 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/response/AuthenticationResponse.java @@ -0,0 +1,65 @@ +/* + * 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.registry.web.response; + +/** + * Authentication response for a user login attempt. + */ +public class AuthenticationResponse { + + private final String identity; + private final String username; + private final long expiration; + private final String issuer; + + /** + * Creates an authentication response. The username and how long the authentication is valid in milliseconds + * + * @param identity The user identity + * @param username The username + * @param expiration The expiration in milliseconds + * @param issuer The issuer of the token + */ + public AuthenticationResponse(final String identity, final String username, final long expiration, final String issuer) { + this.identity = identity; + this.username = username; + this.expiration = expiration; + this.issuer = issuer; + } + + public String getIdentity() { + return identity; + } + + public String getUsername() { + return username; + } + + public String getIssuer() { + return issuer; + } + + /** + * Returns the expiration of a given authentication in milliseconds. + * + * @return The expiration in milliseconds + */ + public long getExpiration() { + return expiration; + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/InvalidAuthenticationException.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/InvalidAuthenticationException.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/InvalidAuthenticationException.java new file mode 100644 index 0000000..c7a1aea --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/InvalidAuthenticationException.java @@ -0,0 +1,35 @@ +/* + * 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.registry.web.security; + +import org.springframework.security.core.AuthenticationException; + +/** + * Thrown if the authentication of a given request is invalid. For instance, + * an expired certificate or token. + */ +public class InvalidAuthenticationException extends AuthenticationException { + + public InvalidAuthenticationException(String msg) { + super(msg); + } + + public InvalidAuthenticationException(String msg, Throwable t) { + super(msg, t); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAnonymousUserFilter.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAnonymousUserFilter.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAnonymousUserFilter.java new file mode 100644 index 0000000..3715bc7 --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAnonymousUserFilter.java @@ -0,0 +1,40 @@ +/* + * 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.registry.web.security; + +import org.apache.nifi.registry.authorization.user.NiFiUserDetails; +import org.apache.nifi.registry.authorization.user.StandardNiFiUser; +import org.apache.nifi.registry.web.security.token.NiFiAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +import javax.servlet.http.HttpServletRequest; + +public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter { + + private static final String ANONYMOUS_KEY = "anonymousNifiKey"; + + public NiFiAnonymousUserFilter() { + super(ANONYMOUS_KEY); + } + + @Override + protected Authentication createAuthentication(HttpServletRequest request) { + return new NiFiAuthenticationToken(new NiFiUserDetails(StandardNiFiUser.ANONYMOUS)); + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationFilter.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationFilter.java new file mode 100644 index 0000000..7dfc3dc --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationFilter.java @@ -0,0 +1,154 @@ +/* + * 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.registry.web.security; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.user.NiFiUserUtils; +import org.apache.nifi.registry.properties.NiFiRegistryProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * + */ +public abstract class NiFiAuthenticationFilter extends GenericFilterBean { + + private static final Logger log = LoggerFactory.getLogger(NiFiAuthenticationFilter.class); + + private AuthenticationManager authenticationManager; + private NiFiRegistryProperties properties; + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (log.isDebugEnabled()) { + log.debug("Checking secure context token: " + authentication); + } + + if (requiresAuthentication((HttpServletRequest) request)) { + authenticate((HttpServletRequest) request, (HttpServletResponse) response, chain); + } else { + chain.doFilter(request, response); + } + + } + + private boolean requiresAuthentication(final HttpServletRequest request) { + return NiFiUserUtils.getNiFiUser() == null; + } + + private void authenticate(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException { + String dnChain = null; + try { + final Authentication authenticationRequest = attemptAuthentication(request); + if (authenticationRequest != null) { + // log the request attempt - response details will be logged later + log.info(String.format("Attempting request for (%s) %s %s (source ip: %s)", authenticationRequest.toString(), request.getMethod(), + request.getRequestURL().toString(), request.getRemoteAddr())); + + // attempt to authorize the user + final Authentication authenticated = authenticationManager.authenticate(authenticationRequest); + successfulAuthorization(request, response, authenticated); + } + + // continue + chain.doFilter(request, response); + } catch (final AuthenticationException ae) { + // invalid authentication - always error out + unsuccessfulAuthorization(request, response, ae); + } + } + + /** + * Attempt to extract an authentication attempt from the specified request. + * + * @param request The request + * @return The authentication attempt or null if none is found int he request + */ + public abstract Authentication attemptAuthentication(HttpServletRequest request); + + protected void successfulAuthorization(HttpServletRequest request, HttpServletResponse response, Authentication authResult) { + log.info("Authentication success for " + authResult); + + SecurityContextHolder.getContext().setAuthentication(authResult); + ProxiedEntitiesUtils.successfulAuthorization(request, response, authResult); + } + + protected void unsuccessfulAuthorization(HttpServletRequest request, HttpServletResponse response, AuthenticationException ae) throws IOException { + // populate the response + ProxiedEntitiesUtils.unsuccessfulAuthorization(request, response, ae); + + // set the response status + response.setContentType("text/plain"); + + // write the response message + PrintWriter out = response.getWriter(); + + // use the type of authentication exception to determine the response code + if (ae instanceof InvalidAuthenticationException) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + out.println(ae.getMessage()); + } else if (ae instanceof UntrustedProxyException) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + out.println(ae.getMessage()); + } else if (ae instanceof AuthenticationServiceException) { + log.error(String.format("Unable to authorize: %s", ae.getMessage()), ae); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + out.println(String.format("Unable to authorize: %s", ae.getMessage())); + } else { + log.error(String.format("Unable to authorize: %s", ae.getMessage()), ae); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + out.println("Access is denied."); + } + + // log the failure + log.warn(String.format("Rejecting access to web api: %s", ae.getMessage())); + + // optionally log the stack trace + if (log.isDebugEnabled()) { + log.debug(StringUtils.EMPTY, ae); + } + } + + @Override + public void destroy() { + } + + public void setAuthenticationManager(AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } + + public void setProperties(NiFiRegistryProperties properties) { + this.properties = properties; + } + +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationProvider.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationProvider.java new file mode 100644 index 0000000..6bc052b --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationProvider.java @@ -0,0 +1,84 @@ +/* + * 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.registry.web.security; + +import org.apache.nifi.registry.authorization.Authorizer; +import org.apache.nifi.registry.authorization.Group; +import org.apache.nifi.registry.authorization.ManagedAuthorizer; +import org.apache.nifi.registry.authorization.UserAndGroups; +import org.apache.nifi.registry.authorization.UserGroupProvider; +import org.apache.nifi.registry.properties.NiFiRegistryProperties; +import org.apache.nifi.registry.properties.util.IdentityMapping; +import org.apache.nifi.registry.properties.util.IdentityMappingUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AuthenticationProvider; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Base AuthenticationProvider that provides common functionality to mapping identities. + */ +public abstract class NiFiAuthenticationProvider implements AuthenticationProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(NiFiAuthenticationProvider.class); + + private NiFiRegistryProperties properties; + private Authorizer authorizer; + private List<IdentityMapping> mappings; + + /** + * @param properties the NiFiProperties instance + */ + public NiFiAuthenticationProvider(final NiFiRegistryProperties properties, final Authorizer authorizer) { + this.properties = properties; + this.mappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties)); + this.authorizer = authorizer; + } + + public List<IdentityMapping> getMappings() { + return mappings; + } + + protected String mapIdentity(final String identity) { + return IdentityMappingUtil.mapIdentity(identity, mappings); + } + + protected Set<String> getUserGroups(final String identity) { + return getUserGroups(authorizer, identity); + } + + protected static Set<String> getUserGroups(final Authorizer authorizer, final String userIdentity) { + if (authorizer instanceof ManagedAuthorizer) { + final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer; + final UserGroupProvider userGroupProvider = managedAuthorizer.getAccessPolicyProvider().getUserGroupProvider(); + final UserAndGroups userAndGroups = userGroupProvider.getUserAndGroups(userIdentity); + final Set<Group> userGroups = userAndGroups.getGroups(); + + if (userGroups == null || userGroups.isEmpty()) { + return Collections.EMPTY_SET; + } else { + return userAndGroups.getGroups().stream().map(group -> group.getName()).collect(Collectors.toSet()); + } + } else { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/785cb81f/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationRequestToken.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationRequestToken.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationRequestToken.java new file mode 100644 index 0000000..c1f44ef --- /dev/null +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiAuthenticationRequestToken.java @@ -0,0 +1,41 @@ +/* + * 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.registry.web.security; + +import org.springframework.security.authentication.AbstractAuthenticationToken; + +/** + * Base class for authentication request tokens in NiFI. + */ +public abstract class NiFiAuthenticationRequestToken extends AbstractAuthenticationToken { + + private final String clientAddress; + + /** + * @param clientAddress The address of the client making the request + */ + public NiFiAuthenticationRequestToken(final String clientAddress) { + super(null); + setAuthenticated(false); + this.clientAddress = clientAddress; + } + + public String getClientAddress() { + return clientAddress; + } + +}
