Repository: nifi-registry Updated Branches: refs/heads/master e73e9c065 -> e8ff47d7d
NIFIREG-146 REST API Documentation improvements Improves the REST API documentation and swagger spec, including: - Corrects handling of collection response types in REST API docs - Adds required access policy information in REST API docs - Adds missing required=true tags to swagger spec - Adds missing readOnly-true tags to swagger spec - Adds security definitions to swagger spec - Corrects VersionedConnection.zIndex field name in swagger spec Functionality changes: - Adds authorization check to the getFlowDiff endpoint This closes #103. Signed-off-by: Bryan Bende <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/e8ff47d7 Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/e8ff47d7 Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/e8ff47d7 Branch: refs/heads/master Commit: e8ff47d7d3001a27f87c367572c2a0fb259f5e14 Parents: e73e9c0 Author: Kevin Doran <[email protected]> Authored: Sat Feb 17 15:56:07 2018 -0500 Committer: Bryan Bende <[email protected]> Committed: Fri Mar 9 10:49:47 2018 -0500 ---------------------------------------------------------------------- .../authorization/AccessPolicySummary.java | 10 +- .../registry/authorization/CurrentUser.java | 6 +- .../nifi/registry/authorization/Resource.java | 4 +- .../authorization/ResourcePermissions.java | 20 ++- .../nifi/registry/authorization/Tenant.java | 12 +- .../nifi/registry/authorization/UserGroup.java | 1 - .../org/apache/nifi/registry/bucket/Bucket.java | 8 +- .../apache/nifi/registry/bucket/BucketItem.java | 14 +- .../nifi/registry/flow/VersionedConnection.java | 4 +- .../registry/flow/VersionedFlowSnapshot.java | 4 +- .../flow/VersionedFlowSnapshotMetadata.java | 10 +- nifi-registry-web-api/pom.xml | 11 +- .../registry/web/api/AccessPolicyResource.java | 66 +++++++--- .../nifi/registry/web/api/AccessResource.java | 11 +- .../registry/web/api/ApplicationResource.java | 2 +- .../api/AuthorizableApplicationResource.java | 4 +- .../registry/web/api/BucketFlowResource.java | 128 ++++++++++++++----- .../nifi/registry/web/api/BucketResource.java | 42 ++++-- .../nifi/registry/web/api/FlowResource.java | 8 +- .../nifi/registry/web/api/ItemResource.java | 15 ++- .../nifi/registry/web/api/TenantResource.java | 113 ++++++++++++---- .../resources/swagger/security-definitions.json | 12 ++ .../src/main/resources/templates/operation.hbs | 24 ++-- .../src/test/resources/keys/README.md | 1 + pom.xml | 4 +- 25 files changed, 389 insertions(+), 145 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/AccessPolicySummary.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/AccessPolicySummary.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/AccessPolicySummary.java index 2939b91..525eb19 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/AccessPolicySummary.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/AccessPolicySummary.java @@ -21,7 +21,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** - * Access policy summary of which actions ("read', "write") are allowable for a specified web resource. + * Access policy summary of which actions ("read', "write", "delete") are allowable for a specified web resource. */ @ApiModel("accessPolicySummary") public class AccessPolicySummary { @@ -31,7 +31,7 @@ public class AccessPolicySummary { private String action; private Boolean configurable; - @ApiModelProperty("The id of the policy. Set by server at creation time.") + @ApiModelProperty(value = "The id of the policy. Set by server at creation time.", readOnly = true) public String getIdentifier() { return identifier; } @@ -40,7 +40,8 @@ public class AccessPolicySummary { this.identifier = identifier; } - @ApiModelProperty("The resource for this access policy.") + @ApiModelProperty(value = "The resource for this access policy.", required = true + ) public String getResource() { return resource; } @@ -51,7 +52,8 @@ public class AccessPolicySummary { @ApiModelProperty( value = "The action associated with this access policy.", - allowableValues = "READ, WRITE" + allowableValues = "read, write, delete", + required = true ) public String getAction() { return action; http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/CurrentUser.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/CurrentUser.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/CurrentUser.java index 7b9b4ee..0d21c62 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/CurrentUser.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/CurrentUser.java @@ -26,7 +26,7 @@ public class CurrentUser { private boolean anonymous; private ResourcePermissions resourcePermissions; - @ApiModelProperty("The identity of the current user") + @ApiModelProperty(value = "The identity of the current user", readOnly = true) public String getIdentity() { return identity; } @@ -35,7 +35,7 @@ public class CurrentUser { this.identity = identity; } - @ApiModelProperty("Indicates if the current user is anonymous") + @ApiModelProperty(value = "Indicates if the current user is anonymous", readOnly = true) public boolean isAnonymous() { return anonymous; } @@ -44,7 +44,7 @@ public class CurrentUser { this.anonymous = anonymous; } - @ApiModelProperty("The access that the current user has to top level resources") + @ApiModelProperty(value = "The access that the current user has to top level resources", readOnly = true) public ResourcePermissions getResourcePermissions() { return resourcePermissions; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Resource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Resource.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Resource.java index 139d729..7dd4493 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Resource.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Resource.java @@ -30,7 +30,7 @@ public class Resource { * * @return The name of the resource */ - @ApiModelProperty("The name of the resource.") + @ApiModelProperty(value = "The name of the resource.", readOnly = true) public String getName() { return name; } @@ -44,7 +44,7 @@ public class Resource { * * @return The identifier of the resource */ - @ApiModelProperty("The identifier of the resource.") + @ApiModelProperty(value = "The identifier of the resource.", readOnly = true) public String getIdentifier() { return identifier; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/ResourcePermissions.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/ResourcePermissions.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/ResourcePermissions.java index 78cd10e..80e95c0 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/ResourcePermissions.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/ResourcePermissions.java @@ -27,7 +27,9 @@ public class ResourcePermissions { private Permissions policies = new Permissions(); private Permissions proxy = new Permissions(); - @ApiModelProperty("The access that the current user has to any top level resources (a logical 'OR' of all other values)") + @ApiModelProperty( + value = "The access that the current user has to any top level resources (a logical 'OR' of all other values)", + readOnly = true) public Permissions getAnyTopLevelResource() { return new Permissions() .withCanRead(buckets.getCanRead() @@ -44,7 +46,9 @@ public class ResourcePermissions { || proxy.getCanDelete()); } - @ApiModelProperty("The access that the current user has to the top level /buckets resource of this NiFi Registry (i.e., access to all buckets)") + @ApiModelProperty( + value = "The access that the current user has to the top level /buckets resource of this NiFi Registry (i.e., access to all buckets)", + readOnly = true) public Permissions getBuckets() { return buckets; } @@ -53,7 +57,9 @@ public class ResourcePermissions { this.buckets = buckets; } - @ApiModelProperty("The access that the current user has to the top level /tenants resource of this NiFi Registry") + @ApiModelProperty( + value = "The access that the current user has to the top level /tenants resource of this NiFi Registry", + readOnly = true) public Permissions getTenants() { return tenants; } @@ -62,7 +68,9 @@ public class ResourcePermissions { this.tenants = tenants; } - @ApiModelProperty("The access that the current user has to the top level /policies resource of this NiFi Registry") + @ApiModelProperty( + value = "The access that the current user has to the top level /policies resource of this NiFi Registry", + readOnly = true) public Permissions getPolicies() { return policies; } @@ -71,7 +79,9 @@ public class ResourcePermissions { this.policies = policies; } - @ApiModelProperty("The access that the current user has to the top level /proxy resource of this NiFi Registry") + @ApiModelProperty( + value = "The access that the current user has to the top level /proxy resource of this NiFi Registry", + readOnly = true) public Permissions getProxy() { return proxy; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Tenant.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Tenant.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Tenant.java index 68c189e..19eee90 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Tenant.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/Tenant.java @@ -45,7 +45,9 @@ public class Tenant { /** * @return tenant's unique identifier */ - @ApiModelProperty(value = "The computer-generated identifier of the tenant.", readOnly = true) + @ApiModelProperty( + value = "The computer-generated identifier of the tenant.", + readOnly = true) public String getIdentifier() { return identifier; } @@ -57,7 +59,9 @@ public class Tenant { /** * @return tenant's identity */ - @ApiModelProperty(value = "The human-facing identity of the tenant. This can only be changed if the tenant is configurable.") + @ApiModelProperty( + value = "The human-facing identity of the tenant. This can only be changed if the tenant is configurable.", + required = true) public String getIdentity() { return identity; } @@ -66,7 +70,9 @@ public class Tenant { this.identity = identity; } - @ApiModelProperty(value = "Indicates if this tenant is configurable, based on which UserGroupProvider has been configured to manage it.", readOnly = true) + @ApiModelProperty( + value = "Indicates if this tenant is configurable, based on which UserGroupProvider has been configured to manage it.", + readOnly = true) public Boolean getConfigurable() { return configurable; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/UserGroup.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/UserGroup.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/UserGroup.java index 1467929..570502d 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/UserGroup.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/authorization/UserGroup.java @@ -30,7 +30,6 @@ import java.util.Set; public class UserGroup extends Tenant { private Set<Tenant> users; - private Set<AccessPolicySummary> accessPolicies; public UserGroup() {} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java index 3c6a59d..94402a9 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java @@ -18,8 +18,8 @@ package org.apache.nifi.registry.bucket; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.apache.nifi.registry.link.LinkableEntity; import org.apache.nifi.registry.authorization.Permissions; +import org.apache.nifi.registry.link.LinkableEntity; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; @@ -43,7 +43,7 @@ public class Bucket extends LinkableEntity { private Permissions permissions; - @ApiModelProperty("An ID to uniquely identify this object.") + @ApiModelProperty(value = "An ID to uniquely identify this object.", readOnly = true) public String getIdentifier() { return identifier; } @@ -52,7 +52,7 @@ public class Bucket extends LinkableEntity { this.identifier = identifier; } - @ApiModelProperty("The name of the bucket.") + @ApiModelProperty(value = "The name of the bucket.", required = true) public String getName() { return name; } @@ -61,7 +61,7 @@ public class Bucket extends LinkableEntity { this.name = name; } - @ApiModelProperty("The timestamp of when the bucket was first created. This is set by the server at creation time.") + @ApiModelProperty(value = "The timestamp of when the bucket was first created. This is set by the server at creation time.", readOnly = true) public long getCreatedTimestamp() { return createdTimestamp; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java index 745bf81..ce9faa7 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/BucketItem.java @@ -18,8 +18,8 @@ package org.apache.nifi.registry.bucket; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.apache.nifi.registry.link.LinkableEntity; import org.apache.nifi.registry.authorization.Permissions; +import org.apache.nifi.registry.link.LinkableEntity; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; @@ -58,7 +58,7 @@ public abstract class BucketItem extends LinkableEntity { this.type = type; } - @ApiModelProperty("An ID to uniquely identify this object.") + @ApiModelProperty(value = "An ID to uniquely identify this object.", readOnly = true) public String getIdentifier() { return identifier; } @@ -67,7 +67,7 @@ public abstract class BucketItem extends LinkableEntity { this.identifier = identifier; } - @ApiModelProperty("The name of the item.") + @ApiModelProperty(value = "The name of the item.", required = true) public String getName() { return name; } @@ -85,7 +85,7 @@ public abstract class BucketItem extends LinkableEntity { this.description = description; } - @ApiModelProperty("The identifier of the bucket this items belongs to.") + @ApiModelProperty(value = "The identifier of the bucket this items belongs to. This cannot be changed after the item is created.", required = true) public String getBucketIdentifier() { return bucketIdentifier; } @@ -103,7 +103,7 @@ public abstract class BucketItem extends LinkableEntity { this.bucketName = bucketName; } - @ApiModelProperty("The timestamp of when the item was created.") + @ApiModelProperty(value = "The timestamp of when the item was created, as milliseconds since epoch.", readOnly = true) public long getCreatedTimestamp() { return createdTimestamp; } @@ -112,7 +112,7 @@ public abstract class BucketItem extends LinkableEntity { this.createdTimestamp = createdTimestamp; } - @ApiModelProperty("The timestamp of when the item was last modified.") + @ApiModelProperty(value = "The timestamp of when the item was last modified, as milliseconds since epoch.", readOnly = true) public long getModifiedTimestamp() { return modifiedTimestamp; } @@ -121,7 +121,7 @@ public abstract class BucketItem extends LinkableEntity { this.modifiedTimestamp = modifiedTimestamp; } - @ApiModelProperty("The type of item.") + @ApiModelProperty(value = "The type of item.", required = true) public BucketItemType getType() { return type; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedConnection.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedConnection.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedConnection.java index 59740e9..4e9fd8e 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedConnection.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedConnection.java @@ -71,7 +71,9 @@ public class VersionedConnection extends VersionedComponent { this.labelIndex = labelIndex; } - @ApiModelProperty("The z index of the connection.") + @ApiModelProperty( + value = "The z index of the connection.", + name = "zIndex") // Jackson maps this method name to JSON key "zIndex", but Swagger does not by default public Long getzIndex() { return zIndex; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshot.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshot.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshot.java index 5384923..bc82397 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshot.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshot.java @@ -54,7 +54,7 @@ public class VersionedFlowSnapshot { private Bucket bucket; - @ApiModelProperty("The metadata for this snapshot") + @ApiModelProperty(value = "The metadata for this snapshot", required = true) public VersionedFlowSnapshotMetadata getSnapshotMetadata() { return snapshotMetadata; } @@ -63,7 +63,7 @@ public class VersionedFlowSnapshot { this.snapshotMetadata = snapshotMetadata; } - @ApiModelProperty("The contents of the versioned flow") + @ApiModelProperty(value = "The contents of the versioned flow", required = true) public VersionedProcessGroup getFlowContents() { return flowContents; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshotMetadata.java ---------------------------------------------------------------------- diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshotMetadata.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshotMetadata.java index 87e9817..2007279 100644 --- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshotMetadata.java +++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/flow/VersionedFlowSnapshotMetadata.java @@ -49,7 +49,7 @@ public class VersionedFlowSnapshotMetadata extends LinkableEntity implements Com private String comments; - @ApiModelProperty("The identifier of the bucket this snapshot belongs to.") + @ApiModelProperty(value = "The identifier of the bucket this snapshot belongs to.", required = true) public String getBucketIdentifier() { return bucketIdentifier; } @@ -58,7 +58,7 @@ public class VersionedFlowSnapshotMetadata extends LinkableEntity implements Com this.bucketIdentifier = bucketIdentifier; } - @ApiModelProperty("The identifier of the flow this snapshot belongs to.") + @ApiModelProperty(value = "The identifier of the flow this snapshot belongs to.", required = true) public String getFlowIdentifier() { return flowIdentifier; } @@ -67,7 +67,7 @@ public class VersionedFlowSnapshotMetadata extends LinkableEntity implements Com this.flowIdentifier = flowIdentifier; } - @ApiModelProperty("The version of this snapshot of the flow.") + @ApiModelProperty(value = "The version of this snapshot of the flow.", required = true) public int getVersion() { return version; } @@ -76,7 +76,7 @@ public class VersionedFlowSnapshotMetadata extends LinkableEntity implements Com this.version = version; } - @ApiModelProperty("The timestamp when the flow was saved.") + @ApiModelProperty(value = "The timestamp when the flow was saved, as milliseconds since epoch.", readOnly = true) public long getTimestamp() { return timestamp; } @@ -85,7 +85,7 @@ public class VersionedFlowSnapshotMetadata extends LinkableEntity implements Com this.timestamp = timestamp; } - @ApiModelProperty("The user that created this snapshot of the flow.") + @ApiModelProperty(value = "The user that created this snapshot of the flow.", readOnly = true) public String getAuthor() { return author; } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/pom.xml b/nifi-registry-web-api/pom.xml index 746fc8b..797f31e 100644 --- a/nifi-registry-web-api/pom.xml +++ b/nifi-registry-web-api/pom.xml @@ -46,7 +46,7 @@ <plugin> <groupId>com.github.kongchen</groupId> <artifactId>swagger-maven-plugin</artifactId> - <version>3.1.5</version> + <version>3.1.6</version> <executions> <execution> <phase>compile</phase> @@ -68,9 +68,7 @@ <title>NiFi Registry REST API</title> <version>${project.version}</version> <description> - The Rest Api provides an interface to a registry with operations for saving, - versioning, reading NiFi flows - and components. + The REST API provides an interface to a registry with operations for saving, versioning, reading NiFi flows and components. </description> <contact> <name>Apache NiFi Registry</name> @@ -82,6 +80,11 @@ <name>Apache 2.0 License</name> </license> </info> + <securityDefinitions> + <securityDefinition> + <jsonPath>${project.basedir}/src/main/resources/swagger/security-definitions.json</jsonPath> + </securityDefinition> + </securityDefinitions> <templatePath>classpath:/templates/index.html.hbs</templatePath> <outputPath> ${project.build.directory}/${project.artifactId}-${project.version}/docs/rest-api/index.html http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java index 68bc493..9950bb3 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java @@ -21,6 +21,11 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.AccessPolicySummary; import org.apache.nifi.registry.authorization.Resource; import org.apache.nifi.registry.exception.ResourceNotFoundException; import org.apache.nifi.registry.security.authorization.Authorizer; @@ -28,8 +33,6 @@ import org.apache.nifi.registry.security.authorization.AuthorizerCapabilityDetec import org.apache.nifi.registry.security.authorization.RequestAction; import org.apache.nifi.registry.security.authorization.resource.Authorizable; import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils; -import org.apache.nifi.registry.authorization.AccessPolicy; -import org.apache.nifi.registry.authorization.AccessPolicySummary; import org.apache.nifi.registry.service.AuthorizationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,8 +61,9 @@ import java.util.List; @Component @Path("/policies") @Api( - value = "/policies", - description = "Endpoint for managing access policies." + value = "policies", + description = "Endpoint for managing access policies.", + authorizations = { @Authorization("Authorization") } ) public class AccessPolicyResource extends AuthorizableApplicationResource { @@ -84,7 +88,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Creates an access policy", - response = AccessPolicy.class + response = AccessPolicy.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -127,7 +136,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets all access policies", response = AccessPolicy.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -158,7 +172,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @Path("{id}") @ApiOperation( value = "Gets an access policy", - response = AccessPolicy.class + response = AccessPolicy.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -196,12 +215,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @Path("{action}/{resource: .+}") @ApiOperation( value = "Gets an access policy for the specified action and resource", - notes = "Will return the effective policy if no specific policy exists for the specified action and resource. " - + "Must have Read permissions to the policy with the desired action and resource. Permissions for the policy that is " - + "returned will be indicated in the response. If the client does not have permissions to that policy, the response " - + "will not include the policy and the permissions in the response will be marked accordingly. If the client does " - + "not have permissions to the policy of the desired action and resource a 403 response will be returned.", - response = AccessPolicy.class + response = AccessPolicy.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -246,7 +265,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @Path("{id}") @ApiOperation( value = "Updates a access policy", - response = AccessPolicy.class + response = AccessPolicy.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -294,7 +318,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @Path("{id}") @ApiOperation( value = "Deletes an access policy", - response = AccessPolicy.class + response = AccessPolicy.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "delete"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -330,7 +359,12 @@ public class AccessPolicyResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets the available resources that support access/authorization policies", response = Resource.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/policies") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java index 1bff31f..0804295 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java @@ -21,6 +21,7 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.authorization.CurrentUser; import org.apache.nifi.registry.exception.AdministrationException; @@ -64,7 +65,7 @@ import java.util.stream.Collectors; @Component @Path("/access") @Api( - value = "/access", + value = "access", description = "Endpoints for obtaining an access token or checking access status." ) public class AccessResource extends ApplicationResource { @@ -105,7 +106,8 @@ public class AccessResource extends ApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Returns the current client's authenticated identity and permissions to top-level resources", - response = CurrentUser.class + response = CurrentUser.class, + authorizations = {@Authorization(value = "Authorization")} ) @ApiResponses({ @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409 + " The NiFi Registry might be running unsecured.") }) @@ -205,14 +207,15 @@ public class AccessResource extends ApplicationResource { "The token returned is formatted as a JSON Web Token (JWT). The token is base64 encoded and comprised of three parts. The header, " + "the body, and the signature. The expiration of the token is a contained within the body. The token can be used in the Authorization header " + "in the format 'Authorization: Bearer <token>'.", - response = String.class + response = String.class, + authorizations = { @Authorization("BasicAuth") } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409 + " The NiFi Registry may not be configured to support login with username/password."), @ApiResponse(code = 500, message = HttpStatusMessages.MESSAGE_500) }) - public Response createAccessTokenUsingFormLogin(@Context HttpServletRequest httpServletRequest) { + public Response createAccessTokenUsingBasicAuthCredentials(@Context HttpServletRequest httpServletRequest) { // only support access tokens when communicating over HTTPS if (!httpServletRequest.isSecure()) { http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ApplicationResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ApplicationResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ApplicationResource.java index 6c4c3ae..ed5c281 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ApplicationResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ApplicationResource.java @@ -42,7 +42,7 @@ public class ApplicationResource { public static final String FORWARDED_PORT_HTTP_HEADER = "X-Forwarded-Port"; public static final String FORWARDED_CONTEXT_HTTP_HEADER = "X-Forwarded-Context"; - protected static final String NON_GUARANTEED_ENDPOINT = "Note: This endpoint is subject to change as NiFi and its REST API evolve."; + protected static final String NON_GUARANTEED_ENDPOINT = "Note: This endpoint is subject to change as NiFi Registry and its REST API evolve."; private static final Logger logger = LoggerFactory.getLogger(ApplicationResource.class); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java index 1d75104..d0be42c 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java @@ -16,13 +16,13 @@ */ package org.apache.nifi.registry.web.api; +import org.apache.nifi.registry.authorization.Resource; +import org.apache.nifi.registry.bucket.BucketItem; import org.apache.nifi.registry.security.authorization.Authorizer; import org.apache.nifi.registry.security.authorization.RequestAction; import org.apache.nifi.registry.security.authorization.resource.Authorizable; import org.apache.nifi.registry.security.authorization.resource.ResourceType; import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils; -import org.apache.nifi.registry.bucket.BucketItem; -import org.apache.nifi.registry.authorization.Resource; import org.apache.nifi.registry.service.AuthorizationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java index e645a40..788f318 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java @@ -21,11 +21,14 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.bucket.BucketItem; +import org.apache.nifi.registry.diff.VersionedFlowDifference; import org.apache.nifi.registry.exception.ResourceNotFoundException; import org.apache.nifi.registry.flow.VersionedFlow; -import org.apache.nifi.registry.diff.VersionedFlowDifference; import org.apache.nifi.registry.flow.VersionedFlowSnapshot; import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; import org.apache.nifi.registry.security.authorization.Authorizer; @@ -58,8 +61,9 @@ import java.util.SortedSet; @Component @Path("/buckets/{bucketId}/flows") @Api( - value = "bucket >> flows", - description = "Create flows scoped to an existing bucket in the registry." + value = "bucket_flows", + description = "Create flows scoped to an existing bucket in the registry.", + authorizations = { @Authorization("Authorization") } ) public class BucketFlowResource extends AuthorizableApplicationResource { @@ -88,7 +92,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @ApiOperation( value = "Creates a flow", notes = "The flow id is created by the server and populated in the returned entity.", - response = VersionedFlow.class + response = VersionedFlow.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -100,7 +109,7 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @PathParam("bucketId") @ApiParam("The bucket identifier") final String bucketId, - @ApiParam("The details of the flow to create.") + @ApiParam(value = "The details of the flow to create.", required = true) final VersionedFlow flow) { authorizeBucketAccess(RequestAction.WRITE, bucketId); @@ -117,7 +126,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets all flows in the given bucket", response = VersionedFlow.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -145,7 +159,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Gets a flow", - response = VersionedFlow.class + response = VersionedFlow.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -176,7 +195,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Updates a flow", - response = VersionedFlow.class + response = VersionedFlow.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -191,14 +215,15 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @PathParam("flowId") @ApiParam("The flow identifier") final String flowId, - @ApiParam("The updated flow") + @ApiParam(value = "The updated flow", required = true) final VersionedFlow flow) { verifyPathParamsMatchBody(bucketId, flowId, flow); - setBucketItemMetadataIfMissing(bucketId, flowId, flow); - authorizeBucketAccess(RequestAction.WRITE, bucketId); + // bucketId and flowId fields are optional in the body parameter, but required before calling the service layer + setBucketItemMetadataIfMissing(bucketId, flowId, flow); + final VersionedFlow updatedFlow = registryService.updateFlow(flow); permissionsService.populateItemPermissions(updatedFlow); linkService.populateFlowLinks(updatedFlow); @@ -211,8 +236,13 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Consumes(MediaType.WILDCARD) @Produces(MediaType.APPLICATION_JSON) @ApiOperation( - value = "Deletes a flow.", - response = VersionedFlow.class + value = "Deletes a flow, including all saved versions of that flow.", + response = VersionedFlow.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "delete"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -238,8 +268,14 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Creates the next version of a flow", - notes = "The version number is created by the server and populated in the returned entity.", - response = VersionedFlowSnapshot.class + notes = "The version number of the object being created must be the next available version integer. " + + "Flow versions are immutable after they are created.", + response = VersionedFlowSnapshot.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -252,14 +288,15 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @ApiParam("The bucket identifier") final String bucketId, @PathParam("flowId") - @ApiParam("The flow identifier") + @ApiParam(value = "The flow identifier") final String flowId, - @ApiParam("The new versioned flow snapshot.") + @ApiParam(value = "The new versioned flow snapshot.", required = true) final VersionedFlowSnapshot snapshot) { verifyPathParamsMatchBody(bucketId, flowId, snapshot); authorizeBucketAccess(RequestAction.WRITE, bucketId); + // bucketId and flowId fields are optional in the body parameter, but required before calling the service layer setSnaphotMetadataIfMissing(bucketId, flowId, snapshot); final String userIdentity = NiFiUserUtils.getNiFiUserIdentity(); @@ -283,7 +320,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets summary information for all versions of a flow. Versions are ordered newest->oldest.", response = VersionedFlowSnapshotMetadata.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -314,7 +356,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Get the latest version of a flow", - response = VersionedFlowSnapshot.class + response = VersionedFlowSnapshot.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -350,7 +397,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Get the metadata for the latest version of a flow", - response = VersionedFlowSnapshotMetadata.class + response = VersionedFlowSnapshotMetadata.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -385,7 +437,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Gets the given version of a flow", - response = VersionedFlowSnapshot.class + response = VersionedFlowSnapshot.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -417,7 +474,12 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Returns a list of differences between 2 versions of a flow", - response = VersionedFlowDifference.class + response = VersionedFlowDifference.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -425,14 +487,20 @@ public class BucketFlowResource extends AuthorizableApplicationResource { @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403), @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409)}) - public Response getFlowDiff(@PathParam("bucketId") - @ApiParam("The bucket identifier") final String bucketId, - @PathParam("flowId") - @ApiParam("The flow identifier") final String flowId, - @PathParam("versionA") - @ApiParam("The first version number") final Integer versionNumberA, - @PathParam("versionB") - @ApiParam("The second version number") final Integer versionNumberB) { + public Response getFlowDiff( + @PathParam("bucketId") + @ApiParam("The bucket identifier") + final String bucketId, + @PathParam("flowId") + @ApiParam("The flow identifier") + final String flowId, + @PathParam("versionA") + @ApiParam("The first version number") + final Integer versionNumberA, + @PathParam("versionB") + @ApiParam("The second version number") + final Integer versionNumberB) { + authorizeBucketAccess(RequestAction.READ, bucketId); VersionedFlowDifference result = registryService.getFlowDiff(bucketId, flowId, versionNumberA, versionNumberB); return Response.status(Response.Status.OK).entity(result).build(); } http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java index 1034539..f94117d 100644 --- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java +++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java @@ -21,6 +21,9 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.bucket.Bucket; import org.apache.nifi.registry.bucket.BucketItem; @@ -59,9 +62,10 @@ import java.util.Set; @Component @Path("/buckets") @Api( - value = "/buckets", - description = "Create named buckets in the registry to store NiFI objects such flows and extensions. " + - "Search for and retrieve existing buckets." + value = "buckets", + description = "Create named buckets in the registry to store NiFi objects such flows and extensions. " + + "Search for and retrieve existing buckets.", + authorizations = { @Authorization("Authorization") } ) public class BucketResource extends AuthorizableApplicationResource { @@ -94,14 +98,19 @@ public class BucketResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Creates a bucket", - response = Bucket.class + response = Bucket.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @ApiResponse(code = 403, message = HttpStatusMessages.MESSAGE_403) }) public Response createBucket( - @ApiParam("The bucket to create") + @ApiParam(value = "The bucket to create", required = true) final Bucket bucket) { authorizeAccess(RequestAction.WRITE); final Bucket createdBucket = registryService.createBucket(bucket); @@ -151,7 +160,12 @@ public class BucketResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Gets a bucket", - response = Bucket.class + response = Bucket.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 401, message = HttpStatusMessages.MESSAGE_401), @@ -176,7 +190,12 @@ public class BucketResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Updates a bucket", - response = Bucket.class + response = Bucket.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -188,7 +207,7 @@ public class BucketResource extends AuthorizableApplicationResource { @PathParam("bucketId") @ApiParam("The bucket identifier") final String bucketId, - @ApiParam("The updated bucket") + @ApiParam(value = "The updated bucket", required = true) final Bucket bucket) { if (StringUtils.isBlank(bucketId)) { @@ -219,7 +238,12 @@ public class BucketResource extends AuthorizableApplicationResource { @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Deletes a bucket along with all objects stored in the bucket", - response = Bucket.class + response = Bucket.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "delete"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/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 ce11b0d..4ea059e 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 @@ -18,8 +18,9 @@ package org.apache.nifi.registry.web.api; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.apache.nifi.registry.security.authorization.Authorizer; +import io.swagger.annotations.Authorization; import org.apache.nifi.registry.field.Fields; +import org.apache.nifi.registry.security.authorization.Authorizer; import org.apache.nifi.registry.service.AuthorizationService; import org.apache.nifi.registry.service.RegistryService; import org.springframework.beans.factory.annotation.Autowired; @@ -36,8 +37,9 @@ import java.util.Set; @Component @Path("/flows") @Api( - value = "/flows", - description = "Gets metadata about flows." + value = "flows", + description = "Gets metadata about flows.", + authorizations = { @Authorization("Authorization") } ) public class FlowResource extends AuthorizableApplicationResource { http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/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 315b442..645f34d 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 @@ -21,6 +21,9 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; import org.apache.nifi.registry.bucket.BucketItem; import org.apache.nifi.registry.field.Fields; import org.apache.nifi.registry.security.authorization.Authorizer; @@ -51,8 +54,9 @@ import java.util.Set; @Component @Path("/items") @Api( - value = "/items", - description = "Retrieve items across all buckets for which the user is authorized." + value = "items", + description = "Retrieve items across all buckets for which the user is authorized.", + authorizations = { @Authorization("Authorization") } ) public class ItemResource extends AuthorizableApplicationResource { @@ -124,7 +128,12 @@ public class ItemResource extends AuthorizableApplicationResource { value = "Gets items of the given bucket", response = BucketItem.class, responseContainer = "List", - nickname = "getItemsInBucket" + nickname = "getItemsInBucket", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/buckets/{bucketId}") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/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 index 1d838c4..2fc2e97 100644 --- 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 @@ -21,15 +21,18 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.authorization.User; +import org.apache.nifi.registry.authorization.UserGroup; import org.apache.nifi.registry.exception.ResourceNotFoundException; import org.apache.nifi.registry.security.authorization.Authorizer; import org.apache.nifi.registry.security.authorization.AuthorizerCapabilityDetection; import org.apache.nifi.registry.security.authorization.RequestAction; import org.apache.nifi.registry.security.authorization.resource.Authorizable; import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils; -import org.apache.nifi.registry.authorization.User; -import org.apache.nifi.registry.authorization.UserGroup; import org.apache.nifi.registry.service.AuthorizationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +61,8 @@ import java.util.List; @Path("tenants") @Api( value = "tenants", - description = "Endpoint for managing users and user groups." + description = "Endpoint for managing users and user groups.", + authorizations = { @Authorization("Authorization") } ) public class TenantResource extends AuthorizableApplicationResource { @@ -88,7 +92,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Creates a user", notes = NON_GUARANTEED_ENDPOINT, - response = User.class + response = User.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -97,7 +106,8 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) public Response createUser( - @Context final HttpServletRequest httpServletRequest, + @Context + final HttpServletRequest httpServletRequest, @ApiParam(value = "The user configuration details.", required = true) final User requestUser) { @@ -134,7 +144,12 @@ public class TenantResource extends AuthorizableApplicationResource { value = "Gets all users", notes = NON_GUARANTEED_ENDPOINT, response = User.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -166,7 +181,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets a user", notes = NON_GUARANTEED_ENDPOINT, - response = User.class + response = User.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -204,7 +224,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Updates a user", notes = NON_GUARANTEED_ENDPOINT, - response = User.class + response = User.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -213,9 +238,11 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) public Response updateUser( - @Context final HttpServletRequest httpServletRequest, + @Context + final HttpServletRequest httpServletRequest, @ApiParam(value = "The user id.", required = true) - @PathParam("id") final String identifier, + @PathParam("id") + final String identifier, @ApiParam(value = "The user configuration details.", required = true) final User requestUser) { @@ -254,7 +281,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Deletes a user", notes = NON_GUARANTEED_ENDPOINT, - response = User.class + response = User.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "delete"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -263,9 +295,11 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) public Response removeUser( - @Context final HttpServletRequest httpServletRequest, + @Context + final HttpServletRequest httpServletRequest, @ApiParam(value = "The user id.", required = true) - @PathParam("id") final String identifier) { + @PathParam("id") + final String identifier) { verifyAuthorizerSupportsConfigurableUserGroups(); authorizeAccess(RequestAction.DELETE); @@ -296,7 +330,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Creates a user group", notes = NON_GUARANTEED_ENDPOINT, - response = UserGroup.class + response = UserGroup.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -305,11 +344,10 @@ public class TenantResource extends AuthorizableApplicationResource { @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) { + @Context + final HttpServletRequest httpServletRequest, + @ApiParam(value = "The user group configuration details.", required = true) + final UserGroup requestUserGroup) { verifyAuthorizerSupportsConfigurableUserGroups(); authorizeAccess(RequestAction.WRITE); @@ -343,7 +381,12 @@ public class TenantResource extends AuthorizableApplicationResource { value = "Gets all user groups", notes = NON_GUARANTEED_ENDPOINT, response = UserGroup.class, - responseContainer = "List" + responseContainer = "List", + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -372,7 +415,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Gets a user group", notes = NON_GUARANTEED_ENDPOINT, - response = UserGroup.class + response = UserGroup.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "read"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -411,7 +459,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Updates a user group", notes = NON_GUARANTEED_ENDPOINT, - response = UserGroup.class + response = UserGroup.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "write"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -420,9 +473,11 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) public Response updateUserGroup( - @Context final HttpServletRequest httpServletRequest, + @Context + final HttpServletRequest httpServletRequest, @ApiParam(value = "The user group id.", required = true) - @PathParam("id") final String identifier, + @PathParam("id") + final String identifier, @ApiParam(value = "The user group configuration details.", required = true) final UserGroup requestUserGroup) { @@ -462,7 +517,12 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiOperation( value = "Deletes a user group", notes = NON_GUARANTEED_ENDPOINT, - response = UserGroup.class + response = UserGroup.class, + extensions = { + @Extension(name = "access-policy", properties = { + @ExtensionProperty(name = "action", value = "delete"), + @ExtensionProperty(name = "resource", value = "/tenants") }) + } ) @ApiResponses({ @ApiResponse(code = 400, message = HttpStatusMessages.MESSAGE_400), @@ -471,7 +531,8 @@ public class TenantResource extends AuthorizableApplicationResource { @ApiResponse(code = 404, message = HttpStatusMessages.MESSAGE_404), @ApiResponse(code = 409, message = HttpStatusMessages.MESSAGE_409) }) public Response removeUserGroup( - @Context final HttpServletRequest httpServletRequest, + @Context + final HttpServletRequest httpServletRequest, @ApiParam(value = "The user group id.", required = true) @PathParam("id") final String identifier) { http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/resources/swagger/security-definitions.json ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/resources/swagger/security-definitions.json b/nifi-registry-web-api/src/main/resources/swagger/security-definitions.json new file mode 100644 index 0000000..411fb3b --- /dev/null +++ b/nifi-registry-web-api/src/main/resources/swagger/security-definitions.json @@ -0,0 +1,12 @@ +{ + "BasicAuth": { + "type": "basic", + "description": "HTTP Basic Auth" + }, + "Authorization": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "description": "NiFi Registry Auth Token (JWT)" + } +} http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/main/resources/templates/operation.hbs ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/main/resources/templates/operation.hbs b/nifi-registry-web-api/src/main/resources/templates/operation.hbs index 5fb25e7..64bd582 100644 --- a/nifi-registry-web-api/src/main/resources/templates/operation.hbs +++ b/nifi-registry-web-api/src/main/resources/templates/operation.hbs @@ -83,7 +83,15 @@ <td>{{@key}}</td> <td> {{#if schema}} - {{#schema.$ref}}<a class="type-link" href="javascript:void(0);">{{basename schema.$ref}}</a>{{/schema.$ref}} + {{#ifeq schema.type "array"}} + {{#if schema.items.$ref}} + array[<a class="type-link" href="javascript:void(0);">{{basename schema.items.$ref}}</a>] + {{else}} + array[{{schema.items.type}}] + {{/if}} + {{else}} + {{#schema.$ref}}<a class="type-link" href="javascript:void(0);">{{basename schema.$ref}}</a>{{/schema.$ref}} + {{/ifeq}} {{else}} string {{/if}} @@ -93,12 +101,10 @@ {{/each}} </tbody> </table> - <div class="title">Authorization</div> - <div class="authorization details"> - {{#security}} - {{#each this}} - <div>{{@key}}</div> - {{/each}} - {{/security}} - </div> + {{#if vendorExtensions.x-access-policy}} + <div class="title">Authorization</div> + <div class="authorization details"> + Requires access policy: {{vendorExtensions.x-access-policy.action}}:{{vendorExtensions.x-access-policy.resource}} + </div> + {{/if}} </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/nifi-registry-web-api/src/test/resources/keys/README.md ---------------------------------------------------------------------- diff --git a/nifi-registry-web-api/src/test/resources/keys/README.md b/nifi-registry-web-api/src/test/resources/keys/README.md index c49bc18..c3059cf 100644 --- a/nifi-registry-web-api/src/test/resources/keys/README.md +++ b/nifi-registry-web-api/src/test/resources/keys/README.md @@ -37,6 +37,7 @@ The steps for generating replacements are: You should now have a directory with the following contents: + keys/ +-- client-ks.jks # client keystore: keystorePass=clientKeystorePassword, keyPass=u1Pass +-- localhost-ks.jks # server keystore: keystorePass=localhostKeystorePassword, keyPass=localhostKeystorePassword http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/e8ff47d7/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index d3e8fbb..2a0634c 100644 --- a/pom.xml +++ b/pom.xml @@ -695,7 +695,9 @@ <exclude>.github/PULL_REQUEST_TEMPLATE.md </exclude> <!-- PR Template for GitHub that does not have a mechanism of including comments --> <exclude>**/resources/banner.txt - </exclude><!-- Console banner text that does not have a mechanism of including comments --> + </exclude> <!-- Console banner text that does not have a mechanism of including comments --> + <exclude>src/main/resources/swagger/security-definitions.json + </exclude> <!-- A maven-swagger-plugin input file that does not have a mechanism of including comments --> </excludes> </configuration> <dependencies>
