From 0c7a7ffa3ea051d81da028cb4bc92e8a3361440e Mon Sep 17 00:00:00 2001 From: nscuro Date: Thu, 16 May 2024 22:21:23 +0200 Subject: [PATCH] Migrate from Swagger v2 to OpenAPI v3 * Migrates from Swagger Core v1.x (OpenAPI 2.0) to Swagger Core v2.x (OpenAPI 3.0) * Adds declaration for multiple `securityScheme`s (API key and Bearer), where the previous solution only supported one (API key) * Removes reliance on Alpine to provide a Swagger servlet, instead use a dedicated JAX-RS resource for it BREAKING CHANGES: * Support for OpenAPI 2.0 is dropped * OpenAPI spec is now exposed via `/api/openapi.json` and `/api/openapi.yaml` - `/api/swagger.json` no longer works Signed-off-by: nscuro --- pom.xml | 11 + .../org/dependencytrack/model/Component.java | 14 +- .../model/PortfolioMetrics.java | 15 +- .../org/dependencytrack/model/Project.java | 6 +- .../dependencytrack/model/ProjectMetrics.java | 15 +- .../resources/OpenApiResource.java | 61 ++++ .../resources/v1/AccessControlResource.java | 77 +++-- .../resources/v1/AnalysisResource.java | 51 +-- .../resources/v1/BadgeResource.java | 78 +++-- .../resources/v1/BomResource.java | 130 ++++---- .../resources/v1/CalculatorResource.java | 41 +-- .../v1/ComponentPropertyResource.java | 76 +++-- .../resources/v1/ComponentResource.java | 195 +++++------ .../resources/v1/ConfigPropertyResource.java | 56 ++-- .../resources/v1/CweResource.java | 51 +-- .../resources/v1/DependencyGraphResource.java | 56 ++-- .../resources/v1/EventResource.java | 33 +- .../resources/v1/FindingResource.java | 169 +++++----- .../resources/v1/IntegrationResource.java | 48 +-- .../resources/v1/LdapResource.java | 83 ++--- .../resources/v1/LicenseGroupResource.java | 128 ++++---- .../resources/v1/LicenseResource.java | 91 +++--- .../resources/v1/MetricsResource.java | 223 ++++++------- .../v1/NotificationPublisherResource.java | 99 +++--- .../v1/NotificationRuleResource.java | 149 +++++---- .../resources/v1/OidcResource.java | 133 ++++---- .../resources/v1/PermissionResource.java | 104 +++--- .../resources/v1/PolicyConditionResource.java | 62 ++-- .../resources/v1/PolicyResource.java | 163 +++++----- .../resources/v1/PolicyViolationResource.java | 90 +++--- .../resources/v1/ProjectPropertyResource.java | 90 +++--- .../resources/v1/ProjectResource.java | 302 ++++++++++-------- .../resources/v1/RepositoryResource.java | 114 ++++--- .../resources/v1/SearchResource.java | 100 +++--- .../resources/v1/ServiceResource.java | 109 ++++--- .../resources/v1/TagResource.java | 43 ++- .../resources/v1/TeamResource.java | 157 ++++----- .../resources/v1/UserResource.java | 265 +++++++-------- .../resources/v1/VexResource.java | 87 +++-- .../v1/ViolationAnalysisResource.java | 50 +-- .../resources/v1/VulnerabilityResource.java | 261 ++++++++------- .../resources/v1/openapi/PaginatedApi.java | 56 ++-- .../v1/problems/InvalidBomProblemDetails.java | 4 +- .../resources/v1/problems/ProblemDetails.java | 25 +- .../resources/v1/vo/BomSubmitRequest.java | 18 +- .../resources/v1/vo/BomUploadResponse.java | 6 +- .../v1/vo/IsTokenBeingProcessedResponse.java | 6 +- .../webapp/WEB-INF/openapi-configuration.yaml | 17 + src/main/webapp/WEB-INF/web.xml | 6 +- 49 files changed, 2311 insertions(+), 1913 deletions(-) create mode 100644 src/main/java/org/dependencytrack/resources/OpenApiResource.java create mode 100644 src/main/webapp/WEB-INF/openapi-configuration.yaml diff --git a/pom.xml b/pom.xml index e7a5f033dc..efab40706a 100644 --- a/pom.xml +++ b/pom.xml @@ -260,6 +260,17 @@ ${lib.pebble.version} + + io.swagger.core.v3 + swagger-jaxrs2 + ${lib.swagger.version} + + + io.swagger.core.v3 + swagger-jaxrs2-servlet-initializer-v2 + ${lib.swagger.version} + + org.apache.httpcomponents httpclient diff --git a/src/main/java/org/dependencytrack/model/Component.java b/src/main/java/org/dependencytrack/model/Component.java index cd4f92327a..9bd41eba9a 100644 --- a/src/main/java/org/dependencytrack/model/Component.java +++ b/src/main/java/org/dependencytrack/model/Component.java @@ -27,7 +27,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.model.validation.ValidSpdxExpression; import org.dependencytrack.persistence.converter.OrganizationalEntityJsonConverter; @@ -253,7 +253,7 @@ public enum FetchGroup { @Size(max = 786) @com.github.packageurl.validator.PackageURL @JsonDeserialize(using = TrimmedStringDeserializer.class) - @ApiModelProperty(dataType = "string") + @Schema(type = "string") private String purl; @Persistent(defaultFetchGroup = "true") @@ -587,7 +587,7 @@ public void setPurl(String purl) { } @JsonSerialize(using = CustomPackageURLSerializer.class) - @ApiModelProperty(dataType = "string", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(type = "string", accessMode = Schema.AccessMode.READ_ONLY) public PackageURL getPurlCoordinates() { if (purlCoordinates == null) { return null; @@ -785,7 +785,7 @@ public void setRepositoryMeta(RepositoryMetaComponent repositoryMeta) { } @JsonIgnore - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public boolean isNew() { return isNew; } @@ -804,7 +804,7 @@ public void setLastInheritedRiskScore(Double lastInheritedRiskScore) { } @JsonIgnore - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getBomRef() { return bomRef; } @@ -815,7 +815,7 @@ public void setBomRef(String bomRef) { } @JsonIgnore - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public List getLicenseCandidates() { return licenseCandidates; } @@ -826,7 +826,7 @@ public void setLicenseCandidates(final List license } @JsonIgnore - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public JsonObject getCacheResult() { return cacheResult; } diff --git a/src/main/java/org/dependencytrack/model/PortfolioMetrics.java b/src/main/java/org/dependencytrack/model/PortfolioMetrics.java index aeec76cfe8..4136e56b2c 100644 --- a/src/main/java/org/dependencytrack/model/PortfolioMetrics.java +++ b/src/main/java/org/dependencytrack/model/PortfolioMetrics.java @@ -20,8 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; - -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.jdo.annotations.Column; import javax.jdo.annotations.IdGeneratorStrategy; @@ -53,22 +52,22 @@ public class PortfolioMetrics implements Serializable { @Persistent @Column(name = "CRITICAL") - @ApiModelProperty(required = true) + @Schema(required = true) private int critical; @Persistent @Column(name = "HIGH") - @ApiModelProperty(required = true) + @Schema(required = true) private int high; @Persistent @Column(name = "MEDIUM") - @ApiModelProperty(required = true) + @Schema(required = true) private int medium; @Persistent @Column(name = "LOW") - @ApiModelProperty(required = true) + @Schema(required = true) private int low; @Persistent @@ -179,14 +178,14 @@ public class PortfolioMetrics implements Serializable { @Column(name = "FIRST_OCCURRENCE", allowsNull = "false") @NotNull @Index(name = "PORTFOLIOMETRICS_FIRST_OCCURRENCE_IDX") - @ApiModelProperty(required = true, dataType = "number") + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, type = "number") private Date firstOccurrence; @Persistent @Column(name = "LAST_OCCURRENCE", allowsNull = "false") @NotNull @Index(name = "PORTFOLIOMETRICS_LAST_OCCURRENCE_IDX") - @ApiModelProperty(required = true, dataType = "number") + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, type = "number") private Date lastOccurrence; public long getId() { diff --git a/src/main/java/org/dependencytrack/model/Project.java b/src/main/java/org/dependencytrack/model/Project.java index 6c0ad11894..f8fcae99d5 100644 --- a/src/main/java/org/dependencytrack/model/Project.java +++ b/src/main/java/org/dependencytrack/model/Project.java @@ -31,7 +31,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.dependencytrack.persistence.converter.OrganizationalEntityJsonConverter; import org.dependencytrack.resources.v1.serializers.CustomPackageURLSerializer; @@ -199,7 +199,7 @@ public enum FetchGroup { @Size(max = 786) @com.github.packageurl.validator.PackageURL @JsonDeserialize(using = TrimmedStringDeserializer.class) - @ApiModelProperty(dataType = "string") + @Schema(type = "string") private String purl; @Persistent @@ -280,7 +280,7 @@ public enum FetchGroup { private List externalReferences; @Persistent(mappedBy = "project") - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(accessMode = Schema.AccessMode.READ_ONLY) private ProjectMetadata metadata; private transient String bomRef; diff --git a/src/main/java/org/dependencytrack/model/ProjectMetrics.java b/src/main/java/org/dependencytrack/model/ProjectMetrics.java index bfa68856cb..e6272824d3 100644 --- a/src/main/java/org/dependencytrack/model/ProjectMetrics.java +++ b/src/main/java/org/dependencytrack/model/ProjectMetrics.java @@ -20,8 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; - -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.jdo.annotations.Column; import javax.jdo.annotations.IdGeneratorStrategy; @@ -52,22 +51,22 @@ public class ProjectMetrics implements Serializable { @Persistent @Column(name = "PROJECT_ID", allowsNull = "false") - @ApiModelProperty(required = true) + @Schema(required = true) private Project project; @Persistent @Column(name = "CRITICAL") - @ApiModelProperty(required = true) + @Schema(required = true) private int critical; @Persistent @Column(name = "HIGH") - @ApiModelProperty(required = true) + @Schema(required = true) private int high; @Persistent @Column(name = "MEDIUM") - @ApiModelProperty(required = true) + @Schema(required = true) private int medium; @Persistent @@ -175,14 +174,14 @@ public class ProjectMetrics implements Serializable { @Column(name = "FIRST_OCCURRENCE", allowsNull = "false") @NotNull @Index(name = "PROJECTMETRICS_FIRST_OCCURRENCE_IDX") - @ApiModelProperty(required = true, dataType = "number") + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, type = "number") private Date firstOccurrence; @Persistent @Column(name = "LAST_OCCURRENCE", allowsNull = "false") @NotNull @Index(name = "PROJECTMETRICS_LAST_OCCURRENCE_IDX") - @ApiModelProperty(required = true, dataType = "number") + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, type = "number") private Date lastOccurrence; public long getId() { diff --git a/src/main/java/org/dependencytrack/resources/OpenApiResource.java b/src/main/java/org/dependencytrack/resources/OpenApiResource.java new file mode 100644 index 0000000000..84e26f8da3 --- /dev/null +++ b/src/main/java/org/dependencytrack/resources/OpenApiResource.java @@ -0,0 +1,61 @@ +/* + * This file is part of Dependency-Track. + * + * Licensed 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. + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) OWASP Foundation. All Rights Reserved. + */ +package org.dependencytrack.resources; + +import alpine.server.auth.AuthenticationNotRequired; +import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource; +import io.swagger.v3.oas.annotations.Operation; + +import javax.servlet.ServletConfig; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +/** + * @since 4.12.0 + */ +@Path("/openapi.{type:json|yaml}") +public class OpenApiResource extends BaseOpenApiResource { + + @Context + ServletConfig config; + + @Context + Application app; + + @GET + @Produces({MediaType.APPLICATION_JSON, "application/yaml"}) + @Operation(hidden = true) + @AuthenticationNotRequired + public Response getOpenApi( + @Context final HttpHeaders headers, + @Context final UriInfo uriInfo, + @PathParam("type") final String type + ) throws Exception { + return super.getOpenApi(headers, config, app, uriInfo, type); + } + +} diff --git a/src/main/java/org/dependencytrack/resources/v1/AccessControlResource.java b/src/main/java/org/dependencytrack/resources/v1/AccessControlResource.java index 7c81e19339..a2b87a9a6f 100644 --- a/src/main/java/org/dependencytrack/resources/v1/AccessControlResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/AccessControlResource.java @@ -23,13 +23,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Project; import org.dependencytrack.model.validation.ValidUuid; @@ -57,7 +61,11 @@ * @since 3.3.0 */ @Path("/v1/acl") -@Api(value = "acl", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "acl") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class AccessControlResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(AccessControlResource.class); @@ -65,24 +73,26 @@ public class AccessControlResource extends AlpineResource { @GET @Path("/team/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the projects assigned to the specified team", - response = String.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Returns the projects assigned to the specified team", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team could not be found"), + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response retrieveProjects (@ApiParam(value = "The UUID of the team to retrieve mappings for", format = "uuid", required = true) + public Response retrieveProjects (@Parameter(description = "The UUID of the team to retrieve mappings for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive, - @ApiParam(value = "Optionally excludes children projects from being returned", required = false) + @Parameter(description = "Optionally excludes children projects from being returned", required = false) @QueryParam("onlyRoot") boolean onlyRoot) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Team team = qm.getObjectByUuid(Team.class, uuid); @@ -98,15 +108,15 @@ public Response retrieveProjects (@ApiParam(value = "The UUID of the team to ret @PUT @Path("/mapping") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds an ACL mapping", - response = AclMappingRequest.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Adds an ACL mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team or project could not be found"), - @ApiResponse(code = 409, message = "A mapping with the same team and project already exists") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"), + @ApiResponse(responseCode = "409", description = "A mapping with the same team and project already exists") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addMapping(AclMappingRequest request) { @@ -136,19 +146,20 @@ public Response addMapping(AclMappingRequest request) { @DELETE @Path("/mapping/team/{teamUuid}/project/{projectUuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes an ACL mapping", - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Removes an ACL mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team or project could not be found"), + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteMapping( - @ApiParam(value = "The UUID of the team to delete the mapping for", format = "uuid", required = true) + @Parameter(description = "The UUID of the team to delete the mapping for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("teamUuid") @ValidUuid String teamUuid, - @ApiParam(value = "The UUID of the project to delete the mapping for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to delete the mapping for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, teamUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/AnalysisResource.java b/src/main/java/org/dependencytrack/resources/v1/AnalysisResource.java index 19088e2b72..9deb335097 100644 --- a/src/main/java/org/dependencytrack/resources/v1/AnalysisResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/AnalysisResource.java @@ -26,12 +26,15 @@ import alpine.model.UserPrincipal; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Analysis; @@ -61,26 +64,30 @@ * @since 3.1.0 */ @Path("/v1/analysis") -@Api(value = "analysis", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "analysis") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class AnalysisResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Retrieves an analysis trail", - response = Analysis.class, - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Retrieves an analysis trail", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project, component, or vulnerability could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project, component, or vulnerability could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) - public Response retrieveAnalysis(@ApiParam(value = "The UUID of the project", format = "uuid") + public Response retrieveAnalysis(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid")) @QueryParam("project") String projectUuid, - @ApiParam(value = "The UUID of the component", format = "uuid", required = true) + @Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @QueryParam("component") String componentUuid, - @ApiParam(value = "The UUID of the vulnerability", format = "uuid", required = true) + @Parameter(description = "The UUID of the vulnerability", schema = @Schema(type = "string", format = "uuid"), required = true) @QueryParam("vulnerability") String vulnerabilityUuid) { failOnValidationError( new ValidationTask(RegexSequence.Pattern.UUID, projectUuid, "Project is not a valid UUID", false), // this is optional @@ -114,14 +121,14 @@ public Response retrieveAnalysis(@ApiParam(value = "The UUID of the project", fo @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Records an analysis decision", - response = Analysis.class, - notes = "

Requires permission VULNERABILITY_ANALYSIS

" + @Operation( + summary = "Records an analysis decision", + description = "

Requires permission VULNERABILITY_ANALYSIS

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project, component, or vulnerability could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project, component, or vulnerability could not be found") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_ANALYSIS) public Response updateAnalysis(AnalysisRequest request) { diff --git a/src/main/java/org/dependencytrack/resources/v1/BadgeResource.java b/src/main/java/org/dependencytrack/resources/v1/BadgeResource.java index d0f03dfed5..32fc0b10a7 100644 --- a/src/main/java/org/dependencytrack/resources/v1/BadgeResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/BadgeResource.java @@ -22,11 +22,13 @@ import alpine.model.ConfigProperty; import alpine.server.auth.AuthenticationNotRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.model.Project; import org.dependencytrack.model.ProjectMetrics; import org.dependencytrack.model.validation.ValidUuid; @@ -48,7 +50,7 @@ * @since 3.6.0 */ @Path("/v1/badge") -@Api(value = "badge") +@Tag(name = "badge") public class BadgeResource extends AlpineResource { private static final String SVG_MEDIA_TYPE = "image/svg+xml"; @@ -62,18 +64,17 @@ private boolean isBadgeSupportEnabled(final QueryManager qm) { @GET @Path("/vulns/project/{uuid}") @Produces(SVG_MEDIA_TYPE) - @ApiOperation( - value = "Returns current metrics for a specific project", - response = ProjectMetrics.class - ) + @Operation( + summary = "Returns current metrics for a specific project") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Badge support is disabled. No content will be returned."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @AuthenticationNotRequired public Response getProjectVulnerabilitiesBadge( - @ApiParam(value = "The UUID of the project to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { if (isBadgeSupportEnabled(qm)) { @@ -94,20 +95,19 @@ public Response getProjectVulnerabilitiesBadge( @GET @Path("/vulns/project/{name}/{version}") @Produces(SVG_MEDIA_TYPE) - @ApiOperation( - value = "Returns current metrics for a specific project", - response = ProjectMetrics.class - ) + @Operation( + summary = "Returns current metrics for a specific project") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Badge support is disabled. No content will be returned."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @AuthenticationNotRequired public Response getProjectVulnerabilitiesBadge( - @ApiParam(value = "The name of the project to query on", required = true) + @Parameter(description = "The name of the project to query on", required = true) @PathParam("name") String name, - @ApiParam(value = "The version of the project to query on", required = true) + @Parameter(description = "The version of the project to query on", required = true) @PathParam("version") String version) { try (QueryManager qm = new QueryManager()) { if (isBadgeSupportEnabled(qm)) { @@ -128,18 +128,17 @@ public Response getProjectVulnerabilitiesBadge( @GET @Path("/violations/project/{uuid}") @Produces(SVG_MEDIA_TYPE) - @ApiOperation( - value = "Returns a policy violations badge for a specific project", - response = String.class - ) + @Operation( + summary = "Returns a policy violations badge for a specific project") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Badge support is disabled. No content will be returned."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @AuthenticationNotRequired public Response getProjectPolicyViolationsBadge( - @ApiParam(value = "The UUID of the project to retrieve a badge for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve a badge for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { if (isBadgeSupportEnabled(qm)) { @@ -160,20 +159,19 @@ public Response getProjectPolicyViolationsBadge( @GET @Path("/violations/project/{name}/{version}") @Produces(SVG_MEDIA_TYPE) - @ApiOperation( - value = "Returns a policy violations badge for a specific project", - response = String.class - ) + @Operation( + summary = "Returns a policy violations badge for a specific project") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Badge support is disabled. No content will be returned."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @AuthenticationNotRequired public Response getProjectPolicyViolationsBadge( - @ApiParam(value = "The name of the project to query on", required = true) + @Parameter(description = "The name of the project to query on", required = true) @PathParam("name") String name, - @ApiParam(value = "The version of the project to query on", required = true) + @Parameter(description = "The version of the project to query on", required = true) @PathParam("version") String version) { try (QueryManager qm = new QueryManager()) { if (isBadgeSupportEnabled(qm)) { diff --git a/src/main/java/org/dependencytrack/resources/v1/BomResource.java b/src/main/java/org/dependencytrack/resources/v1/BomResource.java index 3ca8ddf599..2b0ddaeba1 100644 --- a/src/main/java/org/dependencytrack/resources/v1/BomResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/BomResource.java @@ -22,12 +22,15 @@ import alpine.event.framework.Event; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.BOMInputStream; import org.apache.commons.lang3.StringUtils; @@ -81,7 +84,11 @@ * @since 3.0.0 */ @Path("/v1/bom") -@Api(value = "bom", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "bom") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class BomResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(BomResource.class); @@ -89,25 +96,25 @@ public class BomResource extends AlpineResource { @GET @Path("/cyclonedx/project/{uuid}") @Produces({CycloneDxMediaType.APPLICATION_CYCLONEDX_XML, CycloneDxMediaType.APPLICATION_CYCLONEDX_JSON, MediaType.APPLICATION_OCTET_STREAM}) - @ApiOperation( - value = "Returns dependency metadata for a project in CycloneDX format", - response = String.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns dependency metadata for a project in CycloneDX format", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response exportProjectAsCycloneDx ( - @ApiParam(value = "The UUID of the project to export", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to export", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The format to output (defaults to JSON)") + @Parameter(description = "The format to output (defaults to JSON)") @QueryParam("format") String format, - @ApiParam(value = "Specifies the CycloneDX variant to export. Value options are 'inventory' and 'withVulnerabilities'. (defaults to 'inventory')") + @Parameter(description = "Specifies the CycloneDX variant to export. Value options are 'inventory' and 'withVulnerabilities'. (defaults to 'inventory')") @QueryParam("variant") String variant, - @ApiParam(value = "Force the resulting BOM to be downloaded as a file (defaults to 'false')") + @Parameter(description = "Force the resulting BOM to be downloaded as a file (defaults to 'false')") @QueryParam("download") boolean download) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -159,21 +166,21 @@ public Response exportProjectAsCycloneDx ( @GET @Path("/cyclonedx/component/{uuid}") @Produces(CycloneDxMediaType.APPLICATION_CYCLONEDX_XML) - @ApiOperation( - value = "Returns dependency metadata for a specific component in CycloneDX format", - response = String.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns dependency metadata for a specific component in CycloneDX format", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response exportComponentAsCycloneDx ( - @ApiParam(value = "The UUID of the component to export", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to export", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The format to output (defaults to JSON)") + @Parameter(description = "The format to output (defaults to JSON)") @QueryParam("format") String format) { try (QueryManager qm = new QueryManager()) { final Component component = qm.getObjectByUuid(Component.class, uuid); @@ -205,9 +212,9 @@ public Response exportComponentAsCycloneDx ( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Upload a supported bill of material format document", - notes = """ + @Operation( + summary = "Upload a supported bill of material format document", + description = """

Expects CycloneDX and a valid project UUID. If a UUID is not specified, then the projectName and projectVersion must be specified. @@ -227,17 +234,24 @@ public Response exportComponentAsCycloneDx ( as it does not have this limit.

Requires permission BOM_UPLOAD

""", - response = BomUploadResponse.class, - nickname = "UploadBomBase64Encoded" + operationId = "UploadBomBase64Encoded" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid BOM", response = InvalidBomProblemDetails.class), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))), + @ApiResponse( + responseCode = "400", + description = "Invalid BOM", + content = @Content( + schema = @Schema(implementation = InvalidBomProblemDetails.class), + mediaType = ProblemDetails.MEDIA_TYPE_JSON + ) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.BOM_UPLOAD) - public Response uploadBom(@ApiParam(required = true) BomSubmitRequest request) { + public Response uploadBom(@Parameter(required = true) BomSubmitRequest request) { final Validator validator = getValidator(); if (request.getProject() != null) { // behavior in v3.0.0 failOnValidationError( @@ -295,9 +309,9 @@ public Response uploadBom(@ApiParam(required = true) BomSubmitRequest request) { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Upload a supported bill of material format document", - notes = """ + @Operation( + summary = "Upload a supported bill of material format document", + description = """

Expects CycloneDX and a valid project UUID. If a UUID is not specified, then the projectName and projectVersion must be specified. @@ -312,14 +326,21 @@ public Response uploadBom(@ApiParam(required = true) BomSubmitRequest request) { the response's content type will be application/problem+json.

Requires permission BOM_UPLOAD

""", - response = BomUploadResponse.class, - nickname = "UploadBom" + operationId = "UploadBom" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid BOM", response = InvalidBomProblemDetails.class), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))), + @ApiResponse( + responseCode = "400", + description = "Invalid BOM", + content = @Content( + schema = @Schema(implementation = InvalidBomProblemDetails.class), + mediaType = ProblemDetails.MEDIA_TYPE_JSON + ) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.BOM_UPLOAD) public Response uploadBom(@FormDataParam("project") String projectUuid, @@ -329,7 +350,7 @@ public Response uploadBom(@FormDataParam("project") String projectUuid, @FormDataParam("parentName") String parentName, @FormDataParam("parentVersion") String parentVersion, @FormDataParam("parentUUID") String parentUUID, - @ApiParam(type = "string") @FormDataParam("bom") final List artifactParts) { + @Parameter(schema = @Schema(type = "string")) @FormDataParam("bom") final List artifactParts) { if (projectUuid != null) { // behavior in v3.0.0 try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, projectUuid); @@ -374,9 +395,9 @@ public Response uploadBom(@FormDataParam("project") String projectUuid, @GET @Path("/token/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", - notes = """ + @Operation( + summary = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", + description = """

This endpoint is intended to be used in conjunction with uploading a supported BOM document. Upon upload, a token will be returned. The token can then be queried using this endpoint to @@ -389,16 +410,15 @@ determine if any tasks (such as vulnerability analysis) is being performed on th only that no processing is associated with the specified token.

Requires permission BOM_UPLOAD

-

Deprecated. Use /v1/event/token/{uuid} instead.

""", - response = IsTokenBeingProcessedResponse.class - ) +

Deprecated. Use /v1/event/token/{uuid} instead.

""") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = IsTokenBeingProcessedResponse.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.BOM_UPLOAD) @Deprecated(since = "4.11.0") public Response isTokenBeingProcessed ( - @ApiParam(value = "The UUID of the token to query", format = "uuid", required = true) + @Parameter(description = "The UUID of the token to query", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { final boolean value = Event.isEventBeingProcessed(UUID.fromString(uuid)); diff --git a/src/main/java/org/dependencytrack/resources/v1/CalculatorResource.java b/src/main/java/org/dependencytrack/resources/v1/CalculatorResource.java index 6f90d0b81b..a540d2f6eb 100644 --- a/src/main/java/org/dependencytrack/resources/v1/CalculatorResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/CalculatorResource.java @@ -19,12 +19,15 @@ package org.dependencytrack.resources.v1; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import us.springett.cvss.Cvss; import us.springett.cvss.Score; import us.springett.owasp.riskrating.MissingFactorException; @@ -44,21 +47,23 @@ * @since 3.0.0 */ @Path("/v1/calculator") -@Api(value = "calculator", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "calculator") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class CalculatorResource extends AlpineResource { @GET @Path("/cvss") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the CVSS base score, impact sub-score and exploitability sub-score", - response = Score.class - ) + @Operation(summary = "Returns the CVSS base score, impact sub-score and exploitability sub-score") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "number"))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getCvssScores( - @ApiParam(value = "A valid CVSSv2 or CVSSv3 vector", required = true) + @Parameter(description = "A valid CVSSv2 or CVSSv3 vector", required = true) @QueryParam("vector") String vector) { try { final Cvss cvss = Cvss.fromVector(vector); @@ -73,15 +78,13 @@ public Response getCvssScores( @GET @Path("/owasp") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the OWASP Risk Rating likelihood score, technical impact score and business impact score", - response = us.springett.owasp.riskrating.Score.class - ) + @Operation(summary = "Returns the OWASP Risk Rating likelihood score, technical impact score and business impact score") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "number"))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getOwaspRRScores( - @ApiParam(value = "A valid OWASP Risk Rating vector", required = true) + @Parameter(description = "A valid OWASP Risk Rating vector", required = true) @QueryParam("vector") String vector) { try { final OwaspRiskRating owaspRiskRating = OwaspRiskRating.fromVector(vector); diff --git a/src/main/java/org/dependencytrack/resources/v1/ComponentPropertyResource.java b/src/main/java/org/dependencytrack/resources/v1/ComponentPropertyResource.java index 9a90a8c27c..bd686c358a 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ComponentPropertyResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ComponentPropertyResource.java @@ -19,12 +19,16 @@ package org.dependencytrack.resources.v1; import alpine.server.auth.PermissionRequired; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Component; @@ -49,25 +53,28 @@ * @since 4.11.0 */ @Path("/v1/component/{uuid}/property") -@Api(value = "componentProperty", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "componentProperty") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ComponentPropertyResource extends AbstractConfigPropertyResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all ComponentProperties for the specified component", - response = ComponentProperty.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of all ComponentProperties for the specified component", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ComponentProperty.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProperties( - @ApiParam(value = "The UUID of the component to retrieve properties for", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to retrieve properties for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Component component = qm.getObjectByUuid(Component.class, uuid); @@ -97,21 +104,20 @@ public Response getProperties( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new component property", - response = ComponentProperty.class, - code = 201, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Creates a new component property", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found"), - @ApiResponse(code = 409, message = "A property with the specified component/group/name combination already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ComponentProperty.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found"), + @ApiResponse(responseCode = "409", description = "A property with the specified component/group/name combination already exists") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response createProperty( - @ApiParam(value = "The UUID of the component to create a property for", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to create a property for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, ComponentProperty json) { final Validator validator = super.getValidator(); @@ -156,21 +162,21 @@ public Response createProperty( @Path("/{propertyUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a config property", - response = ComponentProperty.class, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Deletes a config property", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component or component property could not be found"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component or component property could not be found"), }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response deleteProperty( - @ApiParam(value = "The UUID of the component to delete a property from", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to delete a property from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid final String componentUuid, - @ApiParam(value = "The UUID of the component property to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the component property to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("propertyUuid") @ValidUuid final String propertyUuid) { try (QueryManager qm = new QueryManager()) { final Component component = qm.getObjectByUuid(Component.class, componentUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/ComponentResource.java b/src/main/java/org/dependencytrack/resources/v1/ComponentResource.java index 23e90d1252..81ab367cf9 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ComponentResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ComponentResource.java @@ -24,13 +24,17 @@ import alpine.server.resources.AlpineResource; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.event.InternalComponentIdentificationEvent; @@ -71,32 +75,38 @@ * @since 3.0.0 */ @Path("/v1/component") -@Api(value = "component", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "component") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ComponentResource extends AlpineResource { @GET @Path("/project/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all components for a given project", - response = Component.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of components"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of all components for a given project", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of components", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Component.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getAllComponents( - @ApiParam(value = "The UUID of the project to retrieve components for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve components for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally exclude recent components so only outdated components are returned", required = false) + @Parameter(description = "Optionally exclude recent components so only outdated components are returned", required = false) @QueryParam("onlyOutdated") boolean onlyOutdated, - @ApiParam(value = "Optionally exclude transitive dependencies so only direct dependencies are returned", required = false) + @Parameter(description = "Optionally exclude transitive dependencies so only direct dependencies are returned", required = false) @QueryParam("onlyDirect") boolean onlyDirect) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -116,21 +126,21 @@ public Response getAllComponents( @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific component", - response = Component.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a specific component", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Component.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getComponentByUuid( - @ApiParam(value = "The UUID of the component to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes third-party metadata about the component from external repositories", required = false) + @Parameter(description = "Optionally includes third-party metadata about the component from external repositories", required = false) @QueryParam("includeRepositoryMetaData") boolean includeRepositoryMetaData) { try (QueryManager qm = new QueryManager()) { final Component component = qm.getObjectByUuid(Component.class, uuid); @@ -158,31 +168,33 @@ public Response getComponentByUuid( @GET @Path("/identity") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of components that have the specified component identity. This resource accepts coordinates (group, name, version) or purl, cpe, or swidTagId", - responseContainer = "List", - response = Component.class, - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of components"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of components that have the specified component identity. This resource accepts coordinates (group, name, version) or purl, cpe, or swidTagId", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of components", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Component.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getComponentByIdentity(@ApiParam(value = "The group of the component") + public Response getComponentByIdentity(@Parameter(description = "The group of the component") @QueryParam("group") String group, - @ApiParam(value = "The name of the component") + @Parameter(description = "The name of the component") @QueryParam("name") String name, - @ApiParam(value = "The version of the component") + @Parameter(description = "The version of the component") @QueryParam("version") String version, - @ApiParam(value = "The purl of the component") + @Parameter(description = "The purl of the component") @QueryParam("purl") String purl, - @ApiParam(value = "The cpe of the component") + @Parameter(description = "The cpe of the component") @QueryParam("cpe") String cpe, - @ApiParam(value = "The swidTagId of the component") + @Parameter(description = "The swidTagId of the component") @QueryParam("swidTagId") String swidTagId, - @ApiParam(value = "The project the component belongs to", format = "uuid") + @Parameter(description = "The project the component belongs to", schema = @Schema(type = "string", format = "uuid")) @QueryParam("project") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { Project project = null; @@ -219,20 +231,22 @@ public Response getComponentByIdentity(@ApiParam(value = "The group of the compo @GET @Path("/hash/{hash}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of components that have the specified hash value", - responseContainer = "List", - response = Component.class, - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of components"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of components that have the specified hash value", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of components", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Component.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getComponentByHash( - @ApiParam(value = "The MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, BLAKE2b-256, BLAKE2b-384, BLAKE2b-512, or BLAKE3 hash of the component to retrieve", required = true) + @Parameter(description = "The MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, BLAKE2b-256, BLAKE2b-384, BLAKE2b-512, or BLAKE3 hash of the component to retrieve", required = true) @PathParam("hash") String hash) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final PaginatedResult result = qm.getComponentByHash(hash); @@ -244,19 +258,18 @@ public Response getComponentByHash( @Path("/project/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new component", - response = Component.class, - code = 201, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Creates a new component", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Component.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response createComponent(@ApiParam(value = "The UUID of the project to create a component for", format = "uuid", required = true) + public Response createComponent(@Parameter(description = "The UUID of the project to create a component for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, Component jsonComponent) { final Validator validator = super.getValidator(); failOnValidationError( @@ -354,15 +367,15 @@ public Response createComponent(@ApiParam(value = "The UUID of the project to cr @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a component", - response = Component.class, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Updates a component", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the component could not be found"), + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Component.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the component could not be found"), }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response updateComponent(Component jsonComponent) { @@ -462,19 +475,19 @@ public Response updateComponent(Component jsonComponent) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a component", - code = 204, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Deletes a component", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the component could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response deleteComponent( - @ApiParam(value = "The UUID of the component to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Component component = qm.getObjectByUuid(Component.class, uuid, Component.FetchGroup.ALL.name()); @@ -494,13 +507,13 @@ public Response deleteComponent( @GET @Path("/internal/identify") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Requests the identification of internal components in the portfolio", - code = 204, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Requests the identification of internal components in the portfolio", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response identifyInternalComponents() { @@ -511,22 +524,24 @@ public Response identifyInternalComponents() { @GET @Path("/project/{projectUuid}/dependencyGraph/{componentUuids}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the expanded dependency graph to every occurrence of a component", - response = Component.class, - responseContainer = "Map", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns the expanded dependency graph to every occurrence of a component", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "- The UUID of the project could not be found\n- The UUID of the component could not be found") + @ApiResponse( + responseCode = "200", + content = @Content(schema = @Schema(type = "object")) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "- The UUID of the project could not be found\n- The UUID of the component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getDependencyGraphForComponent( - @ApiParam(value = "The UUID of the project to get the expanded dependency graph for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to get the expanded dependency graph for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid, - @ApiParam(value = "List of UUIDs of the components (separated by |) to get the expanded dependency graph for", required = true) + @Parameter(description = "List of UUIDs of the components (separated by |) to get the expanded dependency graph for", required = true) @PathParam("componentUuids") String componentUuids) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, projectUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/ConfigPropertyResource.java b/src/main/java/org/dependencytrack/resources/v1/ConfigPropertyResource.java index 4038b4916f..7938dd41f4 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ConfigPropertyResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ConfigPropertyResource.java @@ -20,11 +20,15 @@ import alpine.model.ConfigProperty; import alpine.server.auth.PermissionRequired; -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 io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.persistence.QueryManager; @@ -46,19 +50,22 @@ * @since 3.2.0 */ @Path("/v1/configProperty") -@Api(value = "configProperty", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "configProperty") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ConfigPropertyResource extends AbstractConfigPropertyResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all ConfigProperties for the specified groupName", - response = ConfigProperty.class, - responseContainer = "List", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Returns a list of all ConfigProperties for the specified groupName", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ConfigProperty.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getConfigProperties() { @@ -81,14 +88,14 @@ public Response getConfigProperties() { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a config property", - response = ConfigProperty.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Updates a config property", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The config property could not be found"), + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ConfigProperty.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The config property could not be found"), }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response updateConfigProperty(ConfigProperty json) { @@ -108,15 +115,14 @@ public Response updateConfigProperty(ConfigProperty json) { @Path("aggregate") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates an array of config properties", - response = ConfigProperty.class, - responseContainer = "List", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Updates an array of config properties", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "One or more config properties could not be found"), + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ConfigProperty.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "One or more config properties could not be found"), }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response updateConfigProperty(List list) { diff --git a/src/main/java/org/dependencytrack/resources/v1/CweResource.java b/src/main/java/org/dependencytrack/resources/v1/CweResource.java index 0b46568e8e..d705201f1d 100644 --- a/src/main/java/org/dependencytrack/resources/v1/CweResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/CweResource.java @@ -20,13 +20,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.model.Cwe; import org.dependencytrack.parser.common.resolver.CweResolver; import org.dependencytrack.resources.v1.openapi.PaginatedApi; @@ -45,20 +49,24 @@ * @since 3.0.0 */ @Path("/v1/cwe") -@Api(value = "cwe", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "cwe") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class CweResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all CWEs", - response = Cwe.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of CWEs") - ) + @Operation(summary = "Returns a list of all CWEs") @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of CWEs", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Cwe.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getCwes() { final PaginatedResult cwes = CweResolver.getInstance().all(getAlpineRequest().getPagination()); @@ -68,16 +76,15 @@ public Response getCwes() { @GET @Path("/{cweId}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific CWE", - response = Cwe.class - ) + @Operation( + summary = "Returns a specific CWE") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The CWE could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Cwe.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The CWE could not be found") }) public Response getCwe( - @ApiParam(value = "The CWE ID of the CWE to retrieve", required = true) + @Parameter(description = "The CWE ID of the CWE to retrieve", required = true) @PathParam("cweId") int cweId) { final Cwe cwe = CweResolver.getInstance().lookup(cweId); if (cwe != null) { diff --git a/src/main/java/org/dependencytrack/resources/v1/DependencyGraphResource.java b/src/main/java/org/dependencytrack/resources/v1/DependencyGraphResource.java index 5c338e1368..0005d1940e 100644 --- a/src/main/java/org/dependencytrack/resources/v1/DependencyGraphResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/DependencyGraphResource.java @@ -23,12 +23,16 @@ import alpine.server.resources.AlpineResource; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Component; import org.dependencytrack.model.Project; @@ -62,26 +66,29 @@ * JAX-RS resources for processing requests related to DependencyGraph. */ @Path("/v1/dependencyGraph") -@Api(value = "dependencyGraph", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "dependencyGraph") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class DependencyGraphResource extends AlpineResource { @GET @Path("/project/{uuid}/directDependencies") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of specific components and services from project UUID", - response = DependencyGraphResponse.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of specific components and services from project UUID", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to a specified component is forbidden"), - @ApiResponse(code = 404, message = "Any component can be found"), + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DependencyGraphResponse.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to a specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "Any component can be found"), }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getComponentsAndServicesByProjectUuid(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response getComponentsAndServicesByProjectUuid(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) final @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -109,19 +116,18 @@ public Response getComponentsAndServicesByProjectUuid(@ApiParam(value = "The UUI @Path("/component/{uuid}/directDependencies") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of specific components and services from component UUID", - response = DependencyGraphResponse.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of specific components and services from component UUID", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to a specified component is forbidden"), - @ApiResponse(code = 404, message = "Any component can be found"), + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DependencyGraphResponse.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to a specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "Any component can be found"), }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getComponentsAndServicesByComponentUuid(@ApiParam(value = "The UUID of the component", format = "uuid", required = true) + public Response getComponentsAndServicesByComponentUuid(@Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) final @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Component component = qm.getObjectByUuid(Component.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/EventResource.java b/src/main/java/org/dependencytrack/resources/v1/EventResource.java index 6b4b39e387..ecef631106 100644 --- a/src/main/java/org/dependencytrack/resources/v1/EventResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/EventResource.java @@ -20,12 +20,15 @@ import alpine.event.framework.Event; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.resources.v1.vo.IsTokenBeingProcessedResponse; @@ -44,16 +47,19 @@ * @since 4.11.0 */ @Path("/v1/event") -@Api(value = "event", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "event") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class EventResource extends AlpineResource { @GET @Path("/token/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", - response = IsTokenBeingProcessedResponse.class, - notes = """ + @Operation( + summary = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", + description = """

This endpoint is intended to be used in conjunction with other API calls which return a token for asynchronous tasks. The token can then be queried using this endpoint to determine if the task is complete: @@ -66,10 +72,11 @@ public class EventResource extends AlpineResource {

""" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = IsTokenBeingProcessedResponse.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response isTokenBeingProcessed ( - @ApiParam(value = "The UUID of the token to query", format = "uuid", required = true) + @Parameter(description = "The UUID of the token to query", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { final boolean value = Event.isEventBeingProcessed(UUID.fromString(uuid)); IsTokenBeingProcessedResponse response = new IsTokenBeingProcessedResponse(); diff --git a/src/main/java/org/dependencytrack/resources/v1/FindingResource.java b/src/main/java/org/dependencytrack/resources/v1/FindingResource.java index 7cb425c2b7..ae0e5460b9 100644 --- a/src/main/java/org/dependencytrack/resources/v1/FindingResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/FindingResource.java @@ -26,13 +26,17 @@ import alpine.server.resources.AlpineResource; import io.pebbletemplates.pebble.PebbleEngine; import io.pebbletemplates.pebble.template.PebbleTemplate; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.text.WordUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.event.PolicyEvaluationEvent; @@ -41,11 +45,11 @@ import org.dependencytrack.integrations.FindingPackagingFormat; import org.dependencytrack.model.Component; import org.dependencytrack.model.Finding; -import org.dependencytrack.model.GroupedFinding; import org.dependencytrack.model.Project; import org.dependencytrack.model.Vulnerability; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; +import org.dependencytrack.resources.v1.vo.BomUploadResponse; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; @@ -74,7 +78,11 @@ * @since 3.1.0 */ @Path("/v1/finding") -@Api(value = "finding", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "finding") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class FindingResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(FindingResource.class); @@ -83,24 +91,26 @@ public class FindingResource extends AlpineResource { @GET @Path("/project/{uuid}") @Produces({MediaType.APPLICATION_JSON, MEDIA_TYPE_SARIF_JSON}) - @ApiOperation( - value = "Returns a list of all findings for a specific project or generates SARIF file if Accept: application/sarif+json header is provided", - response = Finding.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of findings"), - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Returns a list of all findings for a specific project or generates SARIF file if Accept: application/sarif+json header is provided", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of findings", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Finding.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) - public Response getFindingsByProject(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response getFindingsByProject(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes suppressed findings") + @Parameter(description = "Optionally includes suppressed findings") @QueryParam("suppressed") boolean suppressed, - @ApiParam(value = "Optionally limit findings to specific sources of vulnerability intelligence") + @Parameter(description = "Optionally limit findings to specific sources of vulnerability intelligence") @QueryParam("source") Vulnerability.Source source, @HeaderParam("accept") String acceptHeader) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { @@ -137,17 +147,18 @@ public Response getFindingsByProject(@ApiParam(value = "The UUID of the project" @GET @Path("/project/{uuid}/export") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the findings for the specified project as FPF", - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Returns the findings for the specified project as FPF", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) - public Response exportFindingsByProject(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response exportFindingsByProject(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -170,19 +181,19 @@ public Response exportFindingsByProject(@ApiParam(value = "The UUID of the proje @POST @Path("/project/{uuid}/analyze") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Triggers Vulnerability Analysis on a specific project", - response = Project.class, - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Triggers Vulnerability Analysis on a specific project", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) public Response analyzeProject( - @ApiParam(value = "The UUID of the project to analyze", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to analyze", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -211,46 +222,48 @@ public Response analyzeProject( @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all findings", - response = Finding.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of findings"), - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Returns a list of all findings", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of findings", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Finding.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) - public Response getAllFindings(@ApiParam(value = "Show inactive projects") + public Response getAllFindings(@Parameter(description = "Show inactive projects") @QueryParam("showInactive") boolean showInactive, - @ApiParam(value = "Show suppressed findings") + @Parameter(description = "Show suppressed findings") @QueryParam("showSuppressed") boolean showSuppressed, - @ApiParam(value = "Filter by severity") + @Parameter(description = "Filter by severity") @QueryParam("severity") String severity, - @ApiParam(value = "Filter by analysis status") + @Parameter(description = "Filter by analysis status") @QueryParam("analysisStatus") String analysisStatus, - @ApiParam(value = "Filter by vendor response") + @Parameter(description = "Filter by vendor response") @QueryParam("vendorResponse") String vendorResponse, - @ApiParam(value = "Filter published from this date") + @Parameter(description = "Filter published from this date") @QueryParam("publishDateFrom") String publishDateFrom, - @ApiParam(value = "Filter published to this date") + @Parameter(description = "Filter published to this date") @QueryParam("publishDateTo") String publishDateTo, - @ApiParam(value = "Filter attributed on from this date") + @Parameter(description = "Filter attributed on from this date") @QueryParam("attributedOnDateFrom") String attributedOnDateFrom, - @ApiParam(value = "Filter attributed on to this date") + @Parameter(description = "Filter attributed on to this date") @QueryParam("attributedOnDateTo") String attributedOnDateTo, - @ApiParam(value = "Filter the text input in these fields") + @Parameter(description = "Filter the text input in these fields") @QueryParam("textSearchField") String textSearchField, - @ApiParam(value = "Filter by this text input") + @Parameter(description = "Filter by this text input") @QueryParam("textSearchInput") String textSearchInput, - @ApiParam(value = "Filter CVSSv2 from this value") + @Parameter(description = "Filter CVSSv2 from this value") @QueryParam("cvssv2From") String cvssv2From, - @ApiParam(value = "Filter CVSSv2 from this Value") + @Parameter(description = "Filter CVSSv2 from this Value") @QueryParam("cvssv2To") String cvssv2To, - @ApiParam(value = "Filter CVSSv3 from this value") + @Parameter(description = "Filter CVSSv3 from this value") @QueryParam("cvssv3From") String cvssv3From, - @ApiParam(value = "Filter CVSSv3 from this Value") + @Parameter(description = "Filter CVSSv3 from this Value") @QueryParam("cvssv3To") String cvssv3To) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Map filters = new HashMap<>(); @@ -275,40 +288,42 @@ public Response getAllFindings(@ApiParam(value = "Show inactive projects") @GET @Path("/grouped") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all findings grouped by vulnerability", - response = GroupedFinding.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of findings"), - notes = "

Requires permission VIEW_VULNERABILITY

" + @Operation( + summary = "Returns a list of all findings grouped by vulnerability", + description = "

Requires permission VIEW_VULNERABILITY

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of findings", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Finding.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), }) @PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY) - public Response getAllFindings(@ApiParam(value = "Show inactive projects") + public Response getAllFindings(@Parameter(description = "Show inactive projects") @QueryParam("showInactive") boolean showInactive, - @ApiParam(value = "Filter by severity") + @Parameter(description = "Filter by severity") @QueryParam("severity") String severity, - @ApiParam(value = "Filter published from this date") + @Parameter(description = "Filter published from this date") @QueryParam("publishDateFrom") String publishDateFrom, - @ApiParam(value = "Filter published to this date") + @Parameter(description = "Filter published to this date") @QueryParam("publishDateTo") String publishDateTo, - @ApiParam(value = "Filter the text input in these fields") + @Parameter(description = "Filter the text input in these fields") @QueryParam("textSearchField") String textSearchField, - @ApiParam(value = "Filter by this text input") + @Parameter(description = "Filter by this text input") @QueryParam("textSearchInput") String textSearchInput, - @ApiParam(value = "Filter CVSSv2 from this value") + @Parameter(description = "Filter CVSSv2 from this value") @QueryParam("cvssv2From") String cvssv2From, - @ApiParam(value = "Filter CVSSv2 to this value") + @Parameter(description = "Filter CVSSv2 to this value") @QueryParam("cvssv2To") String cvssv2To, - @ApiParam(value = "Filter CVSSv3 from this value") + @Parameter(description = "Filter CVSSv3 from this value") @QueryParam("cvssv3From") String cvssv3From, - @ApiParam(value = "Filter CVSSv3 to this value") + @Parameter(description = "Filter CVSSv3 to this value") @QueryParam("cvssv3To") String cvssv3To, - @ApiParam(value = "Filter occurrences in projects from this value") + @Parameter(description = "Filter occurrences in projects from this value") @QueryParam("occurrencesFrom") String occurrencesFrom, - @ApiParam(value = "Filter occurrences in projects to this value") + @Parameter(description = "Filter occurrences in projects to this value") @QueryParam("occurrencesTo") String occurrencesTo) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Map filters = new HashMap<>(); diff --git a/src/main/java/org/dependencytrack/resources/v1/IntegrationResource.java b/src/main/java/org/dependencytrack/resources/v1/IntegrationResource.java index 6f4abe28e9..c68925de89 100644 --- a/src/main/java/org/dependencytrack/resources/v1/IntegrationResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/IntegrationResource.java @@ -20,11 +20,15 @@ import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.tasks.OsvDownloadTask; @@ -37,20 +41,26 @@ import java.util.stream.Collectors; @Path("/v1/integration") -@Api(value = "integration", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "integration") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class IntegrationResource extends AlpineResource { @GET @Path("/osv/ecosystem") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all ecosystems in OSV", - response = String.class, - responseContainer = "List", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Returns a list of all ecosystems in OSV", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + content = @Content(array = @ArraySchema(schema = @Schema(type = "string"))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getAllEcosystems() { @@ -62,14 +72,16 @@ public Response getAllEcosystems() { @GET @Path("/osv/ecosystem/inactive") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of available inactive ecosystems in OSV to be selected by user", - response = String.class, - responseContainer = "List", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Returns a list of available inactive ecosystems in OSV to be selected by user", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + content = @Content(array = @ArraySchema(schema = @Schema(type = "string"))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getInactiveEcosystems() { diff --git a/src/main/java/org/dependencytrack/resources/v1/LdapResource.java b/src/main/java/org/dependencytrack/resources/v1/LdapResource.java index 47580e91a0..be78ab3aba 100644 --- a/src/main/java/org/dependencytrack/resources/v1/LdapResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/LdapResource.java @@ -25,13 +25,17 @@ import alpine.server.auth.PermissionRequired; import alpine.server.cache.CacheManager; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; @@ -60,7 +64,11 @@ * @since 3.3.0 */ @Path("/v1/ldap") -@Api(value = "ldap", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "ldap") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class LdapResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(LdapResource.class); @@ -68,12 +76,9 @@ public class LdapResource extends AlpineResource { @GET @Path("/groups") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the DNs of all accessible groups within the directory", - response = String.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of ldap groups that match the specified search criteria"), - notes = """ + @Operation( + summary = "Returns the DNs of all accessible groups within the directory", + description = """

This API performs a pass-through query to the configured LDAP server. Search criteria results are cached using default Alpine CacheManager policy. @@ -81,7 +86,12 @@ public class LdapResource extends AlpineResource {

Requires permission ACCESS_MANAGEMENT

""" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of ldap groups that match the specified search criteria", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(type = "string"))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response retrieveLdapGroups () { @@ -119,18 +129,17 @@ public Response retrieveLdapGroups () { @GET @Path("/team/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the DNs of all groups mapped to the specified team", - response = String.class, - responseContainer = "List", - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Returns the DNs of all groups mapped to the specified team", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team could not be found"), + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = MappedLdapGroup.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response retrieveLdapGroups (@ApiParam(value = "The UUID of the team to retrieve mappings for", format = "uuid", required = true) + public Response retrieveLdapGroups (@Parameter(description = "The UUID of the team to retrieve mappings for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, uuid); @@ -146,15 +155,15 @@ public Response retrieveLdapGroups (@ApiParam(value = "The UUID of the team to r @PUT @Path("/mapping") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a mapping", - response = MappedLdapGroup.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Adds a mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team could not be found"), - @ApiResponse(code = 409, message = "A mapping with the same team and dn already exists") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = MappedLdapGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team could not be found"), + @ApiResponse(responseCode = "409", description = "A mapping with the same team and dn already exists") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addMapping(MappedLdapGroupRequest request) { @@ -181,18 +190,18 @@ public Response addMapping(MappedLdapGroupRequest request) { @DELETE @Path("/mapping/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes a mapping", - response = MappedLdapGroup.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Removes a mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the mapping could not be found"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the mapping could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteMapping( - @ApiParam(value = "The UUID of the mapping to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the mapping to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final MappedLdapGroup mapping = qm.getObjectByUuid(MappedLdapGroup.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/LicenseGroupResource.java b/src/main/java/org/dependencytrack/resources/v1/LicenseGroupResource.java index 563fce13b7..c7f73f5307 100644 --- a/src/main/java/org/dependencytrack/resources/v1/LicenseGroupResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/LicenseGroupResource.java @@ -21,13 +21,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.License; @@ -56,21 +60,27 @@ * @since 4.0.0 */ @Path("/v1/licenseGroup") -@Api(value = "licenseGroup", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "licenseGroup") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class LicenseGroupResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all license groups", - response = LicenseGroup.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of license groups"), - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Returns a list of all license groups", + description = "

Requires permission POLICY_MANAGEMENT

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of license groups", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = LicenseGroup.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response getLicenseGroups() { @@ -83,18 +93,17 @@ public Response getLicenseGroups() { @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific license group", - response = License.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Returns a specific license group", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license group could not be found") + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license group could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response getLicenseGroup( - @ApiParam(value = "The UUID of the license group to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the license group to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final LicenseGroup licenseGroup = qm.getObjectByUuid(LicenseGroup.class, uuid); @@ -109,15 +118,14 @@ public Response getLicenseGroup( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new license group", - response = LicenseGroup.class, - code = 201, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Creates a new license group", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A license group with the specified name already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = LicenseGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A license group with the specified name already exists") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response createLicenseGroup(LicenseGroup jsonLicenseGroup) { @@ -140,14 +148,14 @@ public Response createLicenseGroup(LicenseGroup jsonLicenseGroup) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a license group", - response = LicenseGroup.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Updates a license group", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license group could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = LicenseGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license group could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response updateLicenseGroup(LicenseGroup jsonLicenseGroup) { @@ -171,18 +179,18 @@ public Response updateLicenseGroup(LicenseGroup jsonLicenseGroup) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a license group", - code = 204, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Deletes a license group", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the license group could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the license group could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response deleteLicenseGroup( - @ApiParam(value = "The UUID of the license group to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the license group to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final LicenseGroup licenseGroup = qm.getObjectByUuid(LicenseGroup.class, uuid); @@ -199,21 +207,21 @@ public Response deleteLicenseGroup( @Path("/{uuid}/license/{licenseUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds the license to the specified license group.", - response = LicenseGroup.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Adds the license to the specified license group.", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The license group already has the specified license assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license group or license could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = LicenseGroup.class))), + @ApiResponse(responseCode = "304", description = "The license group already has the specified license assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license group or license could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response addLicenseToLicenseGroup( - @ApiParam(value = "A valid license group", format = "uuid", required = true) + @Parameter(description = "A valid license group", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "A valid license", format = "uuid", required = true) + @Parameter(description = "A valid license", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("licenseUuid") @ValidUuid String licenseUuid) { try (QueryManager qm = new QueryManager()) { LicenseGroup licenseGroup = qm.getObjectByUuid(LicenseGroup.class, uuid); @@ -239,21 +247,21 @@ public Response addLicenseToLicenseGroup( @Path("/{uuid}/license/{licenseUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes the license from the license group.", - response = LicenseGroup.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Removes the license from the license group.", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The license is not a member with the license group"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license group or license could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = LicenseGroup.class))), + @ApiResponse(responseCode = "304", description = "The license is not a member with the license group"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license group or license could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response removeLicenseFromLicenseGroup( - @ApiParam(value = "A valid license group", format = "uuid", required = true) + @Parameter(description = "A valid license group", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "A valid license", format = "uuid", required = true) + @Parameter(description = "A valid license", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("licenseUuid") @ValidUuid String licenseUuid) { try (QueryManager qm = new QueryManager()) { LicenseGroup licenseGroup = qm.getObjectByUuid(LicenseGroup.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/LicenseResource.java b/src/main/java/org/dependencytrack/resources/v1/LicenseResource.java index 9a730c0a00..db9b9f6d9a 100644 --- a/src/main/java/org/dependencytrack/resources/v1/LicenseResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/LicenseResource.java @@ -22,13 +22,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.License; import org.dependencytrack.persistence.QueryManager; @@ -52,22 +56,26 @@ * @since 3.0.0 */ @Path("/v1/license") -@Api(value = "license", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "license") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class LicenseResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(LicenseResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all licenses with complete metadata for each license", - response = License.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of licenses") - ) + @Operation(summary = "Returns a list of all licenses with complete metadata for each license") @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of licenses", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = License.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getLicenses() { try (QueryManager qm = new QueryManager(getAlpineRequest())) { @@ -79,13 +87,14 @@ public Response getLicenses() { @GET @Path("/concise") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a concise listing of all licenses", - response = License.class, - responseContainer = "List" - ) + @Operation(summary = "Returns a concise listing of all licenses") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of licenses", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = License.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getLicenseListing() { try (QueryManager qm = new QueryManager(getAlpineRequest())) { @@ -97,16 +106,14 @@ public Response getLicenseListing() { @GET @Path("/{licenseId}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific license", - response = License.class - ) + @Operation(summary = "Returns a specific license") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = License.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license could not be found") }) public Response getLicense( - @ApiParam(value = "The SPDX License ID of the license to retrieve", required = true) + @Parameter(description = "The SPDX License ID of the license to retrieve", required = true) @PathParam("licenseId") String licenseId) { try (QueryManager qm = new QueryManager()) { final License license = qm.getLicense(licenseId); @@ -120,14 +127,14 @@ public Response getLicense( @PUT @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new custom license", - response = License.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Creates a new custom license", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A license with the specified ID already exists.") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = License.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A license with the specified ID already exists.") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response createLicense(License jsonLicense) { @@ -151,19 +158,19 @@ public Response createLicense(License jsonLicense) { @DELETE @Path("/{licenseId}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a custom license", - code = 204, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Deletes a custom license", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The license could not be found"), - @ApiResponse(code = 409, message = "Only custom licenses can be deleted.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The license could not be found"), + @ApiResponse(responseCode = "409", description = "Only custom licenses can be deleted.") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response deleteLicense( - @ApiParam(value = "The SPDX License ID of the license to delete", required = true) + @Parameter(description = "The SPDX License ID of the license to delete", required = true) @PathParam("licenseId") String licenseId) { try (QueryManager qm = new QueryManager()) { final License license = qm.getLicense(licenseId); diff --git a/src/main/java/org/dependencytrack/resources/v1/MetricsResource.java b/src/main/java/org/dependencytrack/resources/v1/MetricsResource.java index 5d1322c1d2..92e340c34f 100644 --- a/src/main/java/org/dependencytrack/resources/v1/MetricsResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/MetricsResource.java @@ -21,12 +21,16 @@ import alpine.event.framework.Event; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.time.DateUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.event.ComponentMetricsUpdateEvent; @@ -58,20 +62,23 @@ * @since 3.0.0 */ @Path("/v1/metrics") -@Api(value = "metrics", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "metrics") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class MetricsResource extends AlpineResource { @GET @Path("/vulnerability") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns the sum of all vulnerabilities in the database by year and month", - response = VulnerabilityMetrics.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns the sum of all vulnerabilities in the database by year and month", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = VulnerabilityMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getVulnerabilityMetrics() { @@ -84,13 +91,13 @@ public Response getVulnerabilityMetrics() { @GET @Path("/portfolio/current") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns current metrics for the entire portfolio", - response = PortfolioMetrics.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns current metrics for the entire portfolio", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = PortfolioMetrics.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getPortfolioCurrentMetrics() { @@ -103,20 +110,19 @@ public Response getPortfolioCurrentMetrics() { @GET @Path("/portfolio/since/{date}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns historical metrics for the entire portfolio from a specific date", - notes = """ + @Operation( + summary = "Returns historical metrics for the entire portfolio from a specific date", + description = """

Date format must be YYYYMMDD

-

Requires permission VIEW_PORTFOLIO

""", - response = PortfolioMetrics.class, - responseContainer = "List" +

Requires permission VIEW_PORTFOLIO

""" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PortfolioMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getPortfolioMetricsSince( - @ApiParam(value = "The start date to retrieve metrics for", required = true) + @Parameter(description = "The start date to retrieve metrics for", required = true) @PathParam("date") String date) { final Date since = DateUtil.parseShortDate(date); @@ -132,18 +138,17 @@ public Response getPortfolioMetricsSince( @GET @Path("/portfolio/{days}/days") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns X days of historical metrics for the entire portfolio", - response = PortfolioMetrics.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns X days of historical metrics for the entire portfolio", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = PortfolioMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getPortfolioMetricsXDays( - @ApiParam(value = "The number of days back to retrieve metrics for", required = true) + @Parameter(description = "The number of days back to retrieve metrics for", required = true) @PathParam("days") int days) { final Date since = DateUtils.addDays(new Date(), -days); @@ -156,13 +161,13 @@ public Response getPortfolioMetricsXDays( @GET @Path("/portfolio/refresh") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Requests a refresh of the portfolio metrics", - response = PortfolioMetrics.class, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Requests a refresh of the portfolio metrics", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response RefreshPortfolioMetrics() { @@ -173,19 +178,19 @@ public Response RefreshPortfolioMetrics() { @GET @Path("/project/{uuid}/current") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns current metrics for a specific project", - response = ProjectMetrics.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns current metrics for a specific project", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ProjectMetrics.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectCurrentMetrics( - @ApiParam(value = "The UUID of the project to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -205,24 +210,23 @@ public Response getProjectCurrentMetrics( @GET @Path("/project/{uuid}/since/{date}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns historical metrics for a specific project from a specific date", - notes = """ + @Operation( + summary = "Returns historical metrics for a specific project from a specific date", + description = """

Date format must be YYYYMMDD

-

Requires permission VIEW_PORTFOLIO

""", - response = ProjectMetrics.class, - responseContainer = "List" +

Requires permission VIEW_PORTFOLIO

""" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ProjectMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectMetricsSince( - @ApiParam(value = "The UUID of the project to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The start date to retrieve metrics for", required = true) + @Parameter(description = "The start date to retrieve metrics for", required = true) @PathParam("date") String date) { final Date since = DateUtil.parseShortDate(date); @@ -232,22 +236,21 @@ public Response getProjectMetricsSince( @GET @Path("/project/{uuid}/days/{days}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns X days of historical metrics for a specific project", - response = ProjectMetrics.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns X days of historical metrics for a specific project", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ProjectMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectMetricsXDays( - @ApiParam(value = "The UUID of the project to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The number of days back to retrieve metrics for", required = true) + @Parameter(description = "The number of days back to retrieve metrics for", required = true) @PathParam("days") int days) { final Date since = DateUtils.addDays(new Date(), -days); @@ -257,18 +260,19 @@ public Response getProjectMetricsXDays( @GET @Path("/project/{uuid}/refresh") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Requests a refresh of a specific projects metrics", - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Requests a refresh of a specific projects metrics", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response RefreshProjectMetrics( - @ApiParam(value = "The UUID of the project to refresh metrics on", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to refresh metrics on", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -288,19 +292,19 @@ public Response RefreshProjectMetrics( @GET @Path("/component/{uuid}/current") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns current metrics for a specific component", - response = DependencyMetrics.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns current metrics for a specific component", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = DependencyMetrics.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getComponentCurrentMetrics( - @ApiParam(value = "The UUID of the component to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Component component = qm.getObjectByUuid(Component.class, uuid); @@ -320,24 +324,23 @@ public Response getComponentCurrentMetrics( @GET @Path("/component/{uuid}/since/{date}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns historical metrics for a specific component from a specific date", - notes = """ + @Operation( + summary = "Returns historical metrics for a specific component from a specific date", + description = """

Date format must be YYYYMMDD

-

Requires permission VIEW_PORTFOLIO

""", - response = DependencyMetrics.class, - responseContainer = "List" +

Requires permission VIEW_PORTFOLIO

""" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DependencyMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getComponentMetricsSince( - @ApiParam(value = "The UUID of the component to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The start date to retrieve metrics for", required = true) + @Parameter(description = "The start date to retrieve metrics for", required = true) @PathParam("date") String date) { final Date since = DateUtil.parseShortDate(date); @@ -350,22 +353,21 @@ public Response getComponentMetricsSince( @GET @Path("/component/{uuid}/days/{days}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns X days of historical metrics for a specific component", - response = DependencyMetrics.class, - responseContainer = "List", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns X days of historical metrics for a specific component", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DependencyMetrics.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getComponentMetricsXDays( - @ApiParam(value = "The UUID of the component to retrieve metrics for", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to retrieve metrics for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The number of days back to retrieve metrics for", required = true) + @Parameter(description = "The number of days back to retrieve metrics for", required = true) @PathParam("days") int days) { final Date since = DateUtils.addDays(new Date(), -days); @@ -375,18 +377,19 @@ public Response getComponentMetricsXDays( @GET @Path("/component/{uuid}/refresh") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Requests a refresh of a specific components metrics", - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Requests a refresh of a specific components metrics", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response RefreshComponentMetrics( - @ApiParam(value = "The UUID of the component to refresh metrics on", format = "uuid", required = true) + @Parameter(description = "The UUID of the component to refresh metrics on", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Component component = qm.getObjectByUuid(Component.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/NotificationPublisherResource.java b/src/main/java/org/dependencytrack/resources/v1/NotificationPublisherResource.java index 61aa5953f1..02c4316c63 100644 --- a/src/main/java/org/dependencytrack/resources/v1/NotificationPublisherResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/NotificationPublisherResource.java @@ -24,16 +24,19 @@ import alpine.notification.NotificationLevel; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.ConfigPropertyConstants; import org.dependencytrack.model.NotificationPublisher; -import org.dependencytrack.model.NotificationRule; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.notification.NotificationConstants; import org.dependencytrack.notification.NotificationGroup; @@ -69,21 +72,24 @@ * @since 3.2.0 */ @Path("/v1/notification/publisher") -@Api(value = "notification", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "notification") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class NotificationPublisherResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(NotificationPublisherResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all notification publishers", - response = NotificationPublisher.class, - responseContainer = "List", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Returns a list of all notification publishers", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = NotificationPublisher.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getAllNotificationPublishers() { @@ -96,16 +102,15 @@ public Response getAllNotificationPublishers() { @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new notification publisher", - response = NotificationPublisher.class, - code = 201, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Creates a new notification publisher", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid notification class or trying to modify a default publisher"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "Conflict with an existing publisher's name") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = NotificationPublisher.class))), + @ApiResponse(responseCode = "400", description = "Invalid notification class or trying to modify a default publisher"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "Conflict with an existing publisher's name") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response createNotificationPublisher(NotificationPublisher jsonNotificationPublisher) { @@ -148,16 +153,16 @@ public Response createNotificationPublisher(NotificationPublisher jsonNotificati @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a notification publisher", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Updates a notification publisher", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid notification class or trying to modify a default publisher"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The notification publisher could not be found"), - @ApiResponse(code = 409, message = "Conflict with an existing publisher's name") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationPublisher.class))), + @ApiResponse(responseCode = "400", description = "Invalid notification class or trying to modify a default publisher"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The notification publisher could not be found"), + @ApiResponse(responseCode = "409", description = "Conflict with an existing publisher's name") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response updateNotificationPublisher(NotificationPublisher jsonNotificationPublisher) { @@ -211,18 +216,18 @@ public Response updateNotificationPublisher(NotificationPublisher jsonNotificati @Path("/{notificationPublisherUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a notification publisher and all related notification rules", - code = 204, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Deletes a notification publisher and all related notification rules", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Deleting a default notification publisher is forbidden"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the notification publisher could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "400", description = "Deleting a default notification publisher is forbidden"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the notification publisher could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) - public Response deleteNotificationPublisher(@ApiParam(value = "The UUID of the notification publisher to delete", format = "uuid", required = true) + public Response deleteNotificationPublisher(@Parameter(description = "The UUID of the notification publisher to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("notificationPublisherUuid") @ValidUuid String notificationPublisherUuid) { try (QueryManager qm = new QueryManager()) { final NotificationPublisher notificationPublisher = qm.getObjectByUuid(NotificationPublisher.class, notificationPublisherUuid); @@ -243,12 +248,13 @@ public Response deleteNotificationPublisher(@ApiParam(value = "The UUID of the n @Path("/restoreDefaultTemplates") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Restore the default notification publisher templates using the ones in the solution classpath", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Restore the default notification publisher templates using the ones in the solution classpath", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response restoreDefaultTemplates() { @@ -271,12 +277,13 @@ public Response restoreDefaultTemplates() { @Path("/test/smtp") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Dispatches a SMTP notification test", - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Dispatches a SMTP notification test", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response testSmtpPublisherConfig(@FormParam("destination") String destination) { diff --git a/src/main/java/org/dependencytrack/resources/v1/NotificationRuleResource.java b/src/main/java/org/dependencytrack/resources/v1/NotificationRuleResource.java index edbaa2f12d..c1b2b82c05 100644 --- a/src/main/java/org/dependencytrack/resources/v1/NotificationRuleResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/NotificationRuleResource.java @@ -23,13 +23,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.NotificationPublisher; @@ -61,23 +65,29 @@ * @since 3.2.0 */ @Path("/v1/notification/rule") -@Api(value = "notification", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "notification") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class NotificationRuleResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(NotificationRuleResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all notification rules", - response = NotificationRule.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of notification rules"), - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Returns a list of all notification rules", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of notification rules", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = NotificationRule.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getAllNotificationRules() { @@ -90,15 +100,14 @@ public Response getAllNotificationRules() { @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new notification rule", - response = NotificationRule.class, - code = 201, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Creates a new notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the notification publisher could not be found") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the notification publisher could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response createNotificationRule(NotificationRule jsonRule) { @@ -128,14 +137,14 @@ public Response createNotificationRule(NotificationRule jsonRule) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a notification rule", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Updates a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the notification rule could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the notification rule could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response updateNotificationRule(NotificationRule jsonRule) { @@ -160,14 +169,14 @@ public Response updateNotificationRule(NotificationRule jsonRule) { @DELETE @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a notification rule", - code = 204, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Deletes a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the notification rule could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the notification rule could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response deleteNotificationRule(NotificationRule jsonRule) { @@ -186,21 +195,21 @@ public Response deleteNotificationRule(NotificationRule jsonRule) { @Path("/{ruleUuid}/project/{projectUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a project to a notification rule", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Adds a project to a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The rule already has the specified project assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The notification rule or project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "304", description = "The rule already has the specified project assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The notification rule or project could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response addProjectToRule( - @ApiParam(value = "The UUID of the rule to add a project to", format = "uuid", required = true) + @Parameter(description = "The UUID of the rule to add a project to", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("ruleUuid") @ValidUuid String ruleUuid, - @ApiParam(value = "The UUID of the project to add to the rule", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to add to the rule", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager()) { final NotificationRule rule = qm.getObjectByUuid(NotificationRule.class, ruleUuid); @@ -228,21 +237,21 @@ public Response addProjectToRule( @Path("/{ruleUuid}/project/{projectUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes a project from a notification rule", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Removes a project from a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The rule does not have the specified project assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The notification rule or project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "304", description = "The rule does not have the specified project assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The notification rule or project could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response removeProjectFromRule( - @ApiParam(value = "The UUID of the rule to remove the project from", format = "uuid", required = true) + @Parameter(description = "The UUID of the rule to remove the project from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("ruleUuid") @ValidUuid String ruleUuid, - @ApiParam(value = "The UUID of the project to remove from the rule", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to remove from the rule", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager()) { final NotificationRule rule = qm.getObjectByUuid(NotificationRule.class, ruleUuid); @@ -270,21 +279,21 @@ public Response removeProjectFromRule( @Path("/{ruleUuid}/team/{teamUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a team to a notification rule", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Adds a team to a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The rule already has the specified team assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The notification rule or team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "304", description = "The rule already has the specified team assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The notification rule or team could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response addTeamToRule( - @ApiParam(value = "The UUID of the rule to add a team to", format = "uuid", required = true) + @Parameter(description = "The UUID of the rule to add a team to", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("ruleUuid") @ValidUuid String ruleUuid, - @ApiParam(value = "The UUID of the team to add to the rule", format = "uuid", required = true) + @Parameter(description = "The UUID of the team to add to the rule", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("teamUuid") @ValidUuid String teamUuid) { try (QueryManager qm = new QueryManager()) { final NotificationRule rule = qm.getObjectByUuid(NotificationRule.class, ruleUuid); @@ -312,21 +321,21 @@ public Response addTeamToRule( @Path("/{ruleUuid}/team/{teamUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes a team from a notification rule", - response = NotificationRule.class, - notes = "

Requires permission SYSTEM_CONFIGURATION

" + @Operation( + summary = "Removes a team from a notification rule", + description = "

Requires permission SYSTEM_CONFIGURATION

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The rule does not have the specified team assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The notification rule or team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = NotificationRule.class))), + @ApiResponse(responseCode = "304", description = "The rule does not have the specified team assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The notification rule or team could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response removeTeamFromRule( - @ApiParam(value = "The UUID of the rule to remove the project from", format = "uuid", required = true) + @Parameter(description = "The UUID of the rule to remove the project from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("ruleUuid") @ValidUuid String ruleUuid, - @ApiParam(value = "The UUID of the project to remove from the rule", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to remove from the rule", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("teamUuid") @ValidUuid String teamUuid) { try (QueryManager qm = new QueryManager()) { final NotificationRule rule = qm.getObjectByUuid(NotificationRule.class, ruleUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/OidcResource.java b/src/main/java/org/dependencytrack/resources/v1/OidcResource.java index 9a6f9170f9..6ff1231d4a 100644 --- a/src/main/java/org/dependencytrack/resources/v1/OidcResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/OidcResource.java @@ -26,12 +26,16 @@ import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; import alpine.server.util.OidcUtil; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; @@ -58,7 +62,11 @@ * @since 4.0.0 */ @Path("/v1/oidc") -@Api(value = "oidc", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "oidc") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class OidcResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(OidcResource.class); @@ -66,10 +74,8 @@ public class OidcResource extends AlpineResource { @GET @Path("/available") @Produces(MediaType.TEXT_PLAIN) - @ApiOperation( - value = "Indicates if OpenID Connect is available for this application", - response = Boolean.class - ) + @Operation( + summary = "Indicates if OpenID Connect is available for this application") @AuthenticationNotRequired public Response isAvailable() { return Response.ok(OidcUtil.isOidcAvailable()).build(); @@ -78,14 +84,13 @@ public Response isAvailable() { @GET @Path("/group") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all groups", - response = OidcGroup.class, - responseContainer = "List", - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Returns a list of all groups", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = OidcGroup.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response retrieveGroups() { @@ -99,14 +104,13 @@ public Response retrieveGroups() { @Path("/group") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates group", - response = OidcGroup.class, - code = 201, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Creates group", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = OidcGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response createGroup(final OidcGroup jsonGroup) { @@ -130,13 +134,13 @@ public Response createGroup(final OidcGroup jsonGroup) { @Path("/group") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates group", - response = OidcGroup.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Updates group", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = OidcGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response updateGroup(final OidcGroup jsonGroup) { @@ -162,17 +166,17 @@ public Response updateGroup(final OidcGroup jsonGroup) { @DELETE @Path("/group/{uuid}") @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a group", - code = 204, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Deletes a group", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The group could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The group could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response deleteGroup(@ApiParam(value = "The UUID of the group to delete", format = "uuid", required = true) + public Response deleteGroup(@Parameter(description = "The UUID of the group to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid final String uuid) { try (QueryManager qm = new QueryManager()) { final OidcGroup group = qm.getObjectByUuid(OidcGroup.class, uuid); @@ -190,18 +194,17 @@ public Response deleteGroup(@ApiParam(value = "The UUID of the group to delete", @GET @Path("/group/{uuid}/team") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of teams associated with the specified group", - response = Team.class, - responseContainer = "List", - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Returns a list of teams associated with the specified group", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the mapping could not be found"), + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Team.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the mapping could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response retrieveTeamsMappedToGroup(@ApiParam(value = "The UUID of the mapping to retrieve the team for", format = "uuid", required = true) + public Response retrieveTeamsMappedToGroup(@Parameter(description = "The UUID of the mapping to retrieve the team for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid final String uuid) { try (final QueryManager qm = new QueryManager()) { final OidcGroup oidcGroup = qm.getObjectByUuid(OidcGroup.class, uuid); @@ -220,15 +223,15 @@ public Response retrieveTeamsMappedToGroup(@ApiParam(value = "The UUID of the ma @PUT @Path("/mapping") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a mapping", - response = MappedOidcGroup.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Adds a mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the team or group could not be found"), - @ApiResponse(code = 409, message = "A mapping with the same team and group name already exists") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = MappedOidcGroup.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the team or group could not be found"), + @ApiResponse(responseCode = "409", description = "A mapping with the same team and group name already exists") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addMapping(final MappedOidcGroupRequest request) { @@ -262,17 +265,17 @@ public Response addMapping(final MappedOidcGroupRequest request) { @DELETE @Path("/mapping/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a mapping", - code = 204, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Deletes a mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the mapping could not be found"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the mapping could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response deleteMappingByUuid(@ApiParam(value = "The UUID of the mapping to delete", format = "uuid", required = true) + public Response deleteMappingByUuid(@Parameter(description = "The UUID of the mapping to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid final String uuid) { try (QueryManager qm = new QueryManager()) { final MappedOidcGroup mapping = qm.getObjectByUuid(MappedOidcGroup.class, uuid); @@ -289,19 +292,19 @@ public Response deleteMappingByUuid(@ApiParam(value = "The UUID of the mapping t @DELETE @Path("/group/{groupUuid}/team/{teamUuid}/mapping") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a mapping", - code = 204, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Deletes a mapping", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the mapping could not be found"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the mapping could not be found"), }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) - public Response deleteMapping(@ApiParam(value = "The UUID of the group to delete a mapping for", format = "uuid", required = true) + public Response deleteMapping(@Parameter(description = "The UUID of the group to delete a mapping for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("groupUuid") @ValidUuid final String groupUuid, - @ApiParam(value = "The UUID of the team to delete a mapping for", format = "uuid", required = true) + @Parameter(description = "The UUID of the team to delete a mapping for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("teamUuid") @ValidUuid final String teamUuid) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, teamUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/PermissionResource.java b/src/main/java/org/dependencytrack/resources/v1/PermissionResource.java index 02e2cc168f..418a928fe8 100644 --- a/src/main/java/org/dependencytrack/resources/v1/PermissionResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/PermissionResource.java @@ -24,12 +24,15 @@ import alpine.model.UserPrincipal; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; @@ -53,21 +56,24 @@ * @since 3.0.0 */ @Path("/v1/permission") -@Api(value = "permission", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "permission") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class PermissionResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(PermissionResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all permissions", - response = alpine.model.Permission.class, - responseContainer = "List", - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Returns a list of all permissions", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Permissions.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getAllPermissions() { @@ -81,21 +87,21 @@ public Response getAllPermissions() { @Path("/{permission}/user/{username}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds the permission to the specified username.", - response = UserPrincipal.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Adds the permission to the specified username.", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The user already has the specified permission assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UserPrincipal.class))), + @ApiResponse(responseCode = "304", description = "The user already has the specified permission assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addPermissionToUser( - @ApiParam(value = "A valid username", required = true) + @Parameter(description = "A valid username", required = true) @PathParam("username") String username, - @ApiParam(value = "A valid permission", required = true) + @Parameter(description = "A valid permission", required = true) @PathParam("permission") String permissionName) { try (QueryManager qm = new QueryManager()) { UserPrincipal principal = qm.getUserPrincipal(username); @@ -122,21 +128,21 @@ public Response addPermissionToUser( @Path("/{permission}/user/{username}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes the permission from the user.", - response = UserPrincipal.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Removes the permission from the user.", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The user already has the specified permission assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UserPrincipal.class))), + @ApiResponse(responseCode = "304", description = "The user already has the specified permission assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response removePermissionFromUser( - @ApiParam(value = "A valid username", required = true) + @Parameter(description = "A valid username", required = true) @PathParam("username") String username, - @ApiParam(value = "A valid permission", required = true) + @Parameter(description = "A valid permission", required = true) @PathParam("permission") String permissionName) { try (QueryManager qm = new QueryManager()) { UserPrincipal principal = qm.getUserPrincipal(username); @@ -163,21 +169,21 @@ public Response removePermissionFromUser( @Path("/{permission}/team/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds the permission to the specified team.", - response = Team.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Adds the permission to the specified team.", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The team already has the specified permission assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Team.class))), + @ApiResponse(responseCode = "304", description = "The team already has the specified permission assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addPermissionToTeam( - @ApiParam(value = "A valid team uuid", format = "uuid", required = true) + @Parameter(description = "A valid team uuid", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "A valid permission", required = true) + @Parameter(description = "A valid permission", required = true) @PathParam("permission") String permissionName) { try (QueryManager qm = new QueryManager()) { Team team = qm.getObjectByUuid(Team.class, uuid); @@ -204,21 +210,21 @@ public Response addPermissionToTeam( @Path("/{permission}/team/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes the permission from the team.", - response = Team.class, - notes = "

Requires permission ACCESS_MANAGEMENT

" + @Operation( + summary = "Removes the permission from the team.", + description = "

Requires permission ACCESS_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The team already has the specified permission assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Team.class))), + @ApiResponse(responseCode = "304", description = "The team already has the specified permission assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response removePermissionFromTeam( - @ApiParam(value = "A valid team uuid", format = "uuid", required = true) + @Parameter(description = "A valid team uuid", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "A valid permission", required = true) + @Parameter(description = "A valid permission", required = true) @PathParam("permission") String permissionName) { try (QueryManager qm = new QueryManager()) { Team team = qm.getObjectByUuid(Team.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/PolicyConditionResource.java b/src/main/java/org/dependencytrack/resources/v1/PolicyConditionResource.java index 326dbc7f5a..5c045f77be 100644 --- a/src/main/java/org/dependencytrack/resources/v1/PolicyConditionResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/PolicyConditionResource.java @@ -21,12 +21,15 @@ import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Policy; @@ -52,26 +55,29 @@ * @since 4.0.0 */ @Path("/v1/policy") -@Api(value = "policyCondition", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "policyCondition") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class PolicyConditionResource extends AlpineResource { @PUT @Path("/{uuid}/condition") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new policy condition", - response = PolicyCondition.class, - code = 201, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Creates a new policy condition", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the policy could not be found") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = PolicyCondition.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the policy could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response createPolicyCondition( - @ApiParam(value = "The UUID of the policy", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, PolicyCondition jsonPolicyCondition) { final Validator validator = super.getValidator(); @@ -94,14 +100,14 @@ public Response createPolicyCondition( @Path("/condition") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a policy condition", - response = PolicyCondition.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Updates a policy condition", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the policy condition could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = PolicyCondition.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the policy condition could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response updatePolicyCondition(PolicyCondition jsonPolicyCondition) { @@ -124,18 +130,18 @@ public Response updatePolicyCondition(PolicyCondition jsonPolicyCondition) { @Path("/condition/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a policy condition", - code = 204, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Deletes a policy condition", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the policy condition could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the policy condition could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response deletePolicyCondition( - @ApiParam(value = "The UUID of the policy condition to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy condition to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final PolicyCondition pc = qm.getObjectByUuid(PolicyCondition.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/PolicyResource.java b/src/main/java/org/dependencytrack/resources/v1/PolicyResource.java index c382720831..b455ac94db 100644 --- a/src/main/java/org/dependencytrack/resources/v1/PolicyResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/PolicyResource.java @@ -21,13 +21,16 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Policy; @@ -57,21 +60,27 @@ * @since 4.0.0 */ @Path("/v1/policy") -@Api(value = "policy", authorizations = @Authorization(value = "X-Api-Key")) +@io.swagger.v3.oas.annotations.tags.Tag(name = "policy") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class PolicyResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all policies", - response = Policy.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of policies"), - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Returns a list of all policies", + description = "

Requires permission POLICY_MANAGEMENT

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of policies", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Policy.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response getPolicies() { @@ -84,18 +93,18 @@ public Response getPolicies() { @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Returns a specific policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response getPolicy( - @ApiParam(value = "The UUID of the policy to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, uuid); @@ -110,15 +119,14 @@ public Response getPolicy( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new policy", - response = Policy.class, - code = 201, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Creates a new policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A policy with the specified name already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A policy with the specified name already exists") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response createPolicy(Policy jsonPolicy) { @@ -151,14 +159,14 @@ public Response createPolicy(Policy jsonPolicy) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Updates a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response updatePolicy(Policy jsonPolicy) { @@ -185,18 +193,18 @@ public Response updatePolicy(Policy jsonPolicy) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a policy", - code = 204, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Deletes a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the policy could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the policy could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response deletePolicy( - @ApiParam(value = "The UUID of the policy to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, uuid); @@ -213,21 +221,21 @@ public Response deletePolicy( @Path("/{policyUuid}/project/{projectUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a project to a policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Adds a project to a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The policy already has the specified project assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy or project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "304", description = "The policy already has the specified project assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy or project could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response addProjectToPolicy( - @ApiParam(value = "The UUID of the policy to add a project to", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to add a project to", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("policyUuid") @ValidUuid String policyUuid, - @ApiParam(value = "The UUID of the project to add to the rule", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to add to the rule", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, policyUuid); @@ -252,21 +260,21 @@ public Response addProjectToPolicy( @Path("/{policyUuid}/project/{projectUuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes a project from a policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Removes a project from a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The policy does not have the specified project assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy or project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "304", description = "The policy does not have the specified project assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy or project could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response removeProjectFromPolicy( - @ApiParam(value = "The UUID of the policy to remove the project from", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to remove the project from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("policyUuid") @ValidUuid String policyUuid, - @ApiParam(value = "The UUID of the project to remove from the policy", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to remove from the policy", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("projectUuid") @ValidUuid String projectUuid) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, policyUuid); @@ -291,21 +299,21 @@ public Response removeProjectFromPolicy( @Path("/{policyUuid}/tag/{tagName}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds a tag to a policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Adds a tag to a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The policy already has the specified tag assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy or tag could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Policy.class))), + @ApiResponse(responseCode = "304", description = "The policy already has the specified tag assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy or tag could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response addTagToPolicy( - @ApiParam(value = "The UUID of the policy to add a project to", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to add a project to", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("policyUuid") @ValidUuid String policyUuid, - @ApiParam(value = "The name of the tag to add to the rule", required = true) + @Parameter(description = "The name of the tag to add to the rule", required = true) @PathParam("tagName")String tagName) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, policyUuid); @@ -331,21 +339,20 @@ public Response addTagToPolicy( @Path("/{policyUuid}/tag/{tagName}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes a tag from a policy", - response = Policy.class, - notes = "

Requires permission POLICY_MANAGEMENT

" + @Operation( + summary = "Removes a tag from a policy", + description = "

Requires permission POLICY_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The policy does not have the specified tag assigned"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The policy or tag could not be found") + @ApiResponse(responseCode = "304", description = "The policy does not have the specified tag assigned"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The policy or tag could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_MANAGEMENT) public Response removeTagFromPolicy( - @ApiParam(value = "The UUID of the policy to remove the tag from", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy to remove the tag from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("policyUuid") @ValidUuid String policyUuid, - @ApiParam(value = "The name of the tag to remove from the policy", required = true) + @Parameter(description = "The name of the tag to remove from the policy", required = true) @PathParam("tagName") String tagName) { try (QueryManager qm = new QueryManager()) { final Policy policy = qm.getObjectByUuid(Policy.class, policyUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/PolicyViolationResource.java b/src/main/java/org/dependencytrack/resources/v1/PolicyViolationResource.java index 0f2c89b85d..f6ac7a1590 100644 --- a/src/main/java/org/dependencytrack/resources/v1/PolicyViolationResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/PolicyViolationResource.java @@ -21,13 +21,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Component; import org.dependencytrack.model.PolicyViolation; @@ -54,24 +58,30 @@ * @since 4.0.0 */ @Path("/v1/violation") -@Api(value = "violation", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "violation") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class PolicyViolationResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all policy violations for the entire portfolio", - response = PolicyViolation.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of policy violations"), - notes = "

Requires permission VIEW_POLICY_VIOLATION

" + @Operation( + summary = "Returns a list of all policy violations for the entire portfolio", + description = "

Requires permission VIEW_POLICY_VIOLATION

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of policy violations", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = PolicyViolation.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_POLICY_VIOLATION) - public Response getViolations(@ApiParam(value = "Optionally includes suppressed violations") + public Response getViolations(@Parameter(description = "Optionally includes suppressed violations") @QueryParam("suppressed") boolean suppressed) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final PaginatedResult result = qm.getPolicyViolations(suppressed); @@ -84,23 +94,25 @@ public Response getViolations(@ApiParam(value = "Optionally includes suppressed @GET @Path("/project/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all policy violations for a specific project", - response = PolicyViolation.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of policy violations"), - notes = "

Requires permission VIEW_POLICY_VIOLATION

" + @Operation( + summary = "Returns a list of all policy violations for a specific project", + description = "

Requires permission VIEW_POLICY_VIOLATION

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of policy violations", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = PolicyViolation.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_POLICY_VIOLATION) - public Response getViolationsByProject(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response getViolationsByProject(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes suppressed violations") + @Parameter(description = "Optionally includes suppressed violations") @QueryParam("suppressed") boolean suppressed) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -122,23 +134,25 @@ public Response getViolationsByProject(@ApiParam(value = "The UUID of the projec @GET @Path("/component/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all policy violations for a specific component", - response = PolicyViolation.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of policy violations"), - notes = "

Requires permission VIEW_POLICY_VIOLATION

" + @Operation( + summary = "Returns a list of all policy violations for a specific component", + description = "

Requires permission VIEW_POLICY_VIOLATION

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of policy violations", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = PolicyViolation.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_POLICY_VIOLATION) - public Response getViolationsByComponent(@ApiParam(value = "The UUID of the component", format = "uuid", required = true) + public Response getViolationsByComponent(@Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes suppressed violations") + @Parameter(description = "Optionally includes suppressed violations") @QueryParam("suppressed") boolean suppressed) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Component component = qm.getObjectByUuid(Component.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/ProjectPropertyResource.java b/src/main/java/org/dependencytrack/resources/v1/ProjectPropertyResource.java index e322bae29e..d95b0467ea 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ProjectPropertyResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ProjectPropertyResource.java @@ -19,12 +19,16 @@ package org.dependencytrack.resources.v1; import alpine.server.auth.PermissionRequired; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Project; @@ -52,25 +56,28 @@ * @since 3.4.0 */ @Path("/v1/project/{uuid}/property") -@Api(value = "projectProperty", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "projectProperty") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ProjectPropertyResource extends AbstractConfigPropertyResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all ProjectProperties for the specified project", - response = ProjectProperty.class, - responseContainer = "List", - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Returns a list of all ProjectProperties for the specified project", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ProjectProperty.class)))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response getProperties( - @ApiParam(value = "The UUID of the project to retrieve properties for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve properties for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -100,21 +107,20 @@ public Response getProperties( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new project property", - response = ProjectProperty.class, - code = 201, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Creates a new project property", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found"), - @ApiResponse(code = 409, message = "A property with the specified project/group/name combination already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ProjectProperty.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found"), + @ApiResponse(responseCode = "409", description = "A property with the specified project/group/name combination already exists") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response createProperty( - @ApiParam(value = "The UUID of the project to create a property for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to create a property for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, ProjectProperty json) { final Validator validator = super.getValidator(); @@ -158,19 +164,19 @@ public Response createProperty( @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a project property", - response = ProjectProperty.class, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Updates a project property", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found"), + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ProjectProperty.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found"), }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response updateProperty( - @ApiParam(value = "The UUID of the project to create a property for", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to create a property for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, ProjectProperty json) { final Validator validator = super.getValidator(); @@ -201,19 +207,19 @@ public Response updateProperty( @DELETE @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a config property", - response = ProjectProperty.class, - notes = "

Requires permission PORTFOLIO_MANAGEMENT

" + @Operation( + summary = "Deletes a config property", + description = "

Requires permission PORTFOLIO_MANAGEMENT

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project or project property could not be found"), + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project or project property could not be found"), }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response deleteProperty( - @ApiParam(value = "The UUID of the project to delete a property from", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to delete a property from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, ProjectProperty json) { final Validator validator = super.getValidator(); diff --git a/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java b/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java index 64d9693c14..0a24e8632d 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java @@ -25,13 +25,16 @@ import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; import io.jsonwebtoken.lang.Collections; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.event.CloneProjectEvent; @@ -71,32 +74,38 @@ * @since 3.0.0 */ @Path("/v1/project") -@Api(value = "project", authorizations = @Authorization(value = "X-Api-Key")) +@io.swagger.v3.oas.annotations.tags.Tag(name = "project") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ProjectResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(ProjectResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all projects", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of all projects", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getProjects(@ApiParam(value = "The optional name of the project to query on", required = false) + public Response getProjects(@Parameter(description = "The optional name of the project to query on", required = false) @QueryParam("name") String name, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive, - @ApiParam(value = "Optionally excludes children projects from being returned", required = false) + @Parameter(description = "Optionally excludes children projects from being returned", required = false) @QueryParam("onlyRoot") boolean onlyRoot, - @ApiParam(value = "The UUID of the team which projects shall be excluded", format = "uuid", required = false) + @Parameter(description = "The UUID of the team which projects shall be excluded", schema = @Schema(type = "string", format = "uuid"), required = false) @QueryParam("notAssignedToTeamWithUuid") @ValidUuid String notAssignedToTeamWithUuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { Team notAssignedToTeam = null; @@ -115,19 +124,19 @@ public Response getProjects(@ApiParam(value = "The optional name of the project @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific project", - response = Project.class, - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a specific project", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Project.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProject( - @ApiParam(value = "The UUID of the project to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getProject(uuid); @@ -146,22 +155,22 @@ public Response getProject( @GET @Path("/lookup") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific project by its name and version", - response = Project.class, - nickname = "getProjectByNameAndVersion", - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a specific project by its name and version", + operationId = "getProjectByNameAndVersion", + description = "

Requires permission VIEW_PORTFOLIO

" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Project.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProject( - @ApiParam(value = "The name of the project to query on", required = true) + @Parameter(description = "The name of the project to query on", required = true) @QueryParam("name") String name, - @ApiParam(value = "The version of the project to query on", required = true) + @Parameter(description = "The version of the project to query on", required = true) @QueryParam("version") String version) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getProject(name, version); @@ -180,24 +189,26 @@ public Response getProject( @GET @Path("/tag/{tag}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all projects by tag", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects with the tag"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of all projects by tag", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectsByTag( - @ApiParam(value = "The tag to query on", required = true) + @Parameter(description = "The tag to query on", required = true) @PathParam("tag") String tagString, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive, - @ApiParam(value = "Optionally excludes children projects from being returned", required = false) + @Parameter(description = "Optionally excludes children projects from being returned", required = false) @QueryParam("onlyRoot") boolean onlyRoot) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Tag tag = qm.getTagByName(tagString); @@ -209,24 +220,26 @@ public Response getProjectsByTag( @GET @Path("/classifier/{classifier}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all projects by classifier", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects of the specified classifier"), - notes = "

Requires permission VIEW_PORTFOLIO

" + @Operation( + summary = "Returns a list of all projects by classifier", + description = "

Requires permission VIEW_PORTFOLIO

" ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectsByClassifier( - @ApiParam(value = "The classifier to query on", required = true) + @Parameter(description = "The classifier to query on", required = true) @PathParam("classifier") String classifierString, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive, - @ApiParam(value = "Optionally excludes children projects from being returned", required = false) + @Parameter(description = "Optionally excludes children projects from being returned", required = false) @QueryParam("onlyRoot") boolean onlyRoot) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Classifier classifier = Classifier.valueOf(classifierString); @@ -240,18 +253,17 @@ public Response getProjectsByClassifier( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new project", - notes = """ + @Operation( + summary = "Creates a new project", + description = """

If a parent project exists, parent.uuid is required

Requires permission PORTFOLIO_MANAGEMENT

- """, - response = Project.class, - code = 201 + """ ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = """ + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Project.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = """
  • An inactive Parent cannot be selected as parent, or
  • A project with the specified name already exists
  • @@ -301,15 +313,15 @@ public Response createProject(Project jsonProject) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a project", - response = Project.class, - notes = "

    Requires permission PORTFOLIO_MANAGEMENT

    " + @Operation( + summary = "Updates a project", + description = "

    Requires permission PORTFOLIO_MANAGEMENT

    " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found"), - @ApiResponse(code = 409, message = """ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Project.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found"), + @ApiResponse(responseCode = "409", description = """
    • An inactive Parent cannot be selected as parent, or
    • Project cannot be set to inactive if active children are present, or
    • @@ -370,15 +382,15 @@ public Response updateProject(Project jsonProject) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Partially updates a project", - response = Project.class, - notes = "

      Requires permission PORTFOLIO_MANAGEMENT

      " + @Operation( + summary = "Partially updates a project", + description = "

      Requires permission PORTFOLIO_MANAGEMENT

      " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found"), - @ApiResponse(code = 409, message = """ + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Project.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found"), + @ApiResponse(responseCode = "409", description = """
      • An inactive Parent cannot be selected as parent, or
      • Project cannot be set to inactive if active children are present, or
      • @@ -388,7 +400,7 @@ public Response updateProject(Project jsonProject) { }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response patchProject( - @ApiParam(value = "The UUID of the project to modify", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to modify", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, Project jsonProject) { final Validator validator = getValidator(); @@ -503,19 +515,19 @@ private boolean setIfDifferent(final Project source, final Project target, f @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a project", - code = 204, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Deletes a project", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response deleteProject( - @ApiParam(value = "The UUID of the project to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, uuid, Project.FetchGroup.ALL.name()); @@ -537,14 +549,14 @@ public Response deleteProject( @Path("/clone") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Clones a project", - response = Project.class, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Clones a project", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response cloneProject(CloneProjectRequest jsonRequest) { @@ -577,23 +589,25 @@ public Response cloneProject(CloneProjectRequest jsonRequest) { @GET @Path("/{uuid}/children") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all children for a project", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all children for a project", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getChildrenProjects(@ApiParam(value = "The UUID of the project to get the children from", format = "uuid", required = true) + public Response getChildrenProjects(@Parameter(description = "The UUID of the project to get the children from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -613,26 +627,28 @@ public Response getChildrenProjects(@ApiParam(value = "The UUID of the project t @GET @Path("/{uuid}/children/classifier/{classifier}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all children for a project by classifier", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all children for a project by classifier", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getChildrenProjectsByClassifier( - @ApiParam(value = "The classifier to query on", required = true) + @Parameter(description = "The classifier to query on", required = true) @PathParam("classifier") String classifierString, - @ApiParam(value = "The UUID of the project to get the children from", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to get the children from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -653,26 +669,28 @@ public Response getChildrenProjectsByClassifier( @GET @Path("/{uuid}/children/tag/{tag}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all children for a project by tag", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all children for a project by tag", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getChildrenProjectsByTag( - @ApiParam(value = "The tag to query on", required = true) + @Parameter(description = "The tag to query on", required = true) @PathParam("tag") String tagString, - @ApiParam(value = "The UUID of the project to get the children from", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to get the children from", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -693,26 +711,28 @@ public Response getChildrenProjectsByTag( @GET @Path("/withoutDescendantsOf/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all projects without the descendants of the selected project", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all projects without the descendants of the selected project", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getProjectsWithoutDescendantsOf( - @ApiParam(value = "The UUID of the project which descendants will be excluded", format = "uuid", required = true) + @Parameter(description = "The UUID of the project which descendants will be excluded", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The optional name of the project to query on", required = false) + @Parameter(description = "The optional name of the project to query on", required = false) @QueryParam("name") String name, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/RepositoryResource.java b/src/main/java/org/dependencytrack/resources/v1/RepositoryResource.java index f717b04dd9..172f1a00a3 100644 --- a/src/main/java/org/dependencytrack/resources/v1/RepositoryResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/RepositoryResource.java @@ -24,13 +24,17 @@ import alpine.server.resources.AlpineResource; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Repository; @@ -62,21 +66,27 @@ * @since 3.1.0 */ @Path("/v1/repository") -@Api(value = "repository", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "repository") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class RepositoryResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all repositories", - response = Repository.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of repositories"), - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Returns a list of all repositories", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of repositories", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Repository.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getRepositories() { @@ -89,20 +99,22 @@ public Response getRepositories() { @GET @Path("/{type}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns repositories that support the specific type", - response = Repository.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of repositories"), - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Returns repositories that support the specific type", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of repositories", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Repository.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response getRepositoriesByType( - @ApiParam(value = "The type of repositories to retrieve", required = true) + @Parameter(description = "The type of repositories to retrieve", required = true) @PathParam("type") RepositoryType type) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final PaginatedResult result = qm.getRepositories(type); @@ -113,18 +125,17 @@ public Response getRepositoriesByType( @GET @Path("/latest") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Attempts to resolve the latest version of the component available in the configured repositories", - response = RepositoryMetaComponent.class - ) + @Operation( + summary = "Attempts to resolve the latest version of the component available in the configured repositories") @ApiResponses(value = { - @ApiResponse(code = 204, message = "The request was successful, but no repositories are configured to support the specified Package URL"), - @ApiResponse(code = 400, message = "The specified Package URL is invalid and not in the correct format"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The repository metadata for the specified component cannot be found"), + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = RepositoryMetaComponent.class))), + @ApiResponse(responseCode = "204", description = "The request was successful, but no repositories are configured to support the specified Package URL"), + @ApiResponse(responseCode = "400", description = "The specified Package URL is invalid and not in the correct format"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The repository metadata for the specified component cannot be found"), }) public Response getRepositoryMetaComponent( - @ApiParam(value = "The Package URL for the component to query", required = true) + @Parameter(description = "The Package URL for the component to query", required = true) @QueryParam("purl") String purl) { try { final PackageURL packageURL = new PackageURL(purl); @@ -150,15 +161,14 @@ public Response getRepositoryMetaComponent( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new repository", - response = Repository.class, - code = 201, - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Creates a new repository", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A repository with the specified identifier already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Repository.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A repository with the specified identifier already exists") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response createRepository(Repository jsonRepository) { @@ -190,14 +200,14 @@ public Response createRepository(Repository jsonRepository) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a repository", - response = Repository.class, - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Updates a repository", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the repository could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Repository.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the repository could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response updateRepository(Repository jsonRepository) { @@ -232,18 +242,18 @@ public Response updateRepository(Repository jsonRepository) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a repository", - code = 204, - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Deletes a repository", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The UUID of the repository could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The UUID of the repository could not be found") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response deleteRepository( - @ApiParam(value = "The UUID of the repository to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the repository to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Repository repository = qm.getObjectByUuid(Repository.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/SearchResource.java b/src/main/java/org/dependencytrack/resources/v1/SearchResource.java index 338cc81fe1..7fd24466a9 100644 --- a/src/main/java/org/dependencytrack/resources/v1/SearchResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/SearchResource.java @@ -20,11 +20,14 @@ import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.search.FuzzyVulnerableSoftwareSearchManager; @@ -48,18 +51,22 @@ * @since 3.0.0 */ @Path("/v1/search") -@Api(value = "search", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "search") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class SearchResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response aggregateSearch(@QueryParam("query") String query) { @@ -71,13 +78,13 @@ public Response aggregateSearch(@QueryParam("query") String query) { @Path("/project") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response projectSearch(@QueryParam("query") String query) { @@ -89,13 +96,13 @@ public Response projectSearch(@QueryParam("query") String query) { @Path("/component") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response componentSearch(@QueryParam("query") String query) { @@ -107,13 +114,13 @@ public Response componentSearch(@QueryParam("query") String query) { @Path("/service") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response serviceSearch(@QueryParam("query") String query) { @@ -125,13 +132,13 @@ public Response serviceSearch(@QueryParam("query") String query) { @Path("/license") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response licenseSearch(@QueryParam("query") String query) { @@ -143,13 +150,13 @@ public Response licenseSearch(@QueryParam("query") String query) { @Path("/vulnerability") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response vulnerabilitySearch(@QueryParam("query") String query) { @@ -161,13 +168,13 @@ public Response vulnerabilitySearch(@QueryParam("query") String query) { @Path("/vulnerablesoftware") @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Processes and returns search results", - response = SearchResult.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Processes and returns search results", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = SearchResult.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response vulnerableSoftwareSearch(@QueryParam("query") String query, @QueryParam("cpe") String cpe) { @@ -185,13 +192,14 @@ public Response vulnerableSoftwareSearch(@QueryParam("query") String query, @Que @Path("/reindex") @POST @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Rebuild lucene indexes for search operations", - notes = "

        Requires permission SYSTEM_CONFIGURATION

        " + @Operation( + summary = "Rebuild lucene indexes for search operations", + description = "

        Requires permission SYSTEM_CONFIGURATION

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 400, message = "No valid index type was provided") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "400", description = "No valid index type was provided") }) @PermissionRequired(Permissions.Constants.SYSTEM_CONFIGURATION) public Response reindex(@QueryParam("type") Set type) { diff --git a/src/main/java/org/dependencytrack/resources/v1/ServiceResource.java b/src/main/java/org/dependencytrack/resources/v1/ServiceResource.java index 4c15445028..8926ed1930 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ServiceResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ServiceResource.java @@ -21,13 +21,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Project; @@ -55,27 +59,33 @@ * @since 4.2.0 */ @Path("/v1/service") -@Api(value = "service", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "service") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ServiceResource extends AlpineResource { @GET @Path("/project/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all services for a given project", - response = ServiceComponent.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of services"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all services for a given project", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of services", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ServiceComponent.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getAllServices(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response getAllServices(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -95,19 +105,19 @@ public Response getAllServices(@ApiParam(value = "The UUID of the project", form @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific service", - response = ServiceComponent.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a specific service", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified service is forbidden"), - @ApiResponse(code = 404, message = "The service could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ServiceComponent.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified service is forbidden"), + @ApiResponse(responseCode = "404", description = "The service could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getServiceByUuid( - @ApiParam(value = "The UUID of the service to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the service to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final ServiceComponent service = qm.getObjectByUuid(ServiceComponent.class, uuid); @@ -129,19 +139,18 @@ public Response getServiceByUuid( @Path("/project/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new service", - response = ServiceComponent.class, - code = 201, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Creates a new service", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ServiceComponent.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response createService(@ApiParam(value = "The UUID of the project", format = "uuid", required = true) + public Response createService(@Parameter(description = "The UUID of the project", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, ServiceComponent jsonService) { final Validator validator = super.getValidator(); failOnValidationError( @@ -183,15 +192,15 @@ public Response createService(@ApiParam(value = "The UUID of the project", forma @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a service", - response = ServiceComponent.class, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Updates a service", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified service is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the service could not be found"), + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ServiceComponent.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified service is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the service could not be found"), }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response updateService(ServiceComponent jsonService) { @@ -234,19 +243,19 @@ public Response updateService(ServiceComponent jsonService) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a service", - code = 204, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Deletes a service", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified service is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the service could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified service is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the service could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response deleteService( - @ApiParam(value = "The UUID of the service to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the service to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final ServiceComponent service = qm.getObjectByUuid(ServiceComponent.class, uuid, ServiceComponent.FetchGroup.ALL.name()); diff --git a/src/main/java/org/dependencytrack/resources/v1/TagResource.java b/src/main/java/org/dependencytrack/resources/v1/TagResource.java index 03ddb3d257..b3b4f6f708 100644 --- a/src/main/java/org/dependencytrack/resources/v1/TagResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/TagResource.java @@ -21,17 +21,21 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.Tag; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; +import org.dependencytrack.resources.v1.openapi.PaginatedApi; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -41,24 +45,31 @@ import javax.ws.rs.core.Response; @Path("/v1/tag") -@Api(value = "tag", authorizations = @Authorization(value = "X-Api-Key")) +@io.swagger.v3.oas.annotations.tags.Tag(name = "tag") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class TagResource extends AlpineResource { @GET @Path("/{policyUuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all tags associated with a given policy", - response = Tag.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of tags"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all tags associated with a given policy", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) + @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of tags", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Tag.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getTags(@ApiParam(value = "The UUID of the policy", format = "uuid", required = true) + public Response getTags(@Parameter(description = "The UUID of the policy", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("policyUuid") @ValidUuid String policyUuid){ try (QueryManager qm = new QueryManager(getAlpineRequest())) { final PaginatedResult result = qm.getTags(policyUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/TeamResource.java b/src/main/java/org/dependencytrack/resources/v1/TeamResource.java index a74fbc75d4..af6ca6fcda 100644 --- a/src/main/java/org/dependencytrack/resources/v1/TeamResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/TeamResource.java @@ -24,13 +24,17 @@ import alpine.model.Team; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.persistence.QueryManager; @@ -59,22 +63,28 @@ * @since 3.0.0 */ @Path("/v1/team") -@Api(value = "team", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "team") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class TeamResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(TeamResource.class); @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all teams", - response = Team.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of teams"), - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Returns a list of all teams", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of teams", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Team.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getTeams() { @@ -88,18 +98,18 @@ public Response getTeams() { @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific team", - response = Team.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Returns a specific team", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Team.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getTeam( - @ApiParam(value = "The UUID of the team to retrieve", format = "uuid", required = true) + @Parameter(description = "The UUID of the team to retrieve", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, uuid); @@ -114,14 +124,13 @@ public Response getTeam( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new team along with an associated API key", - response = Team.class, - code = 201, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Creates a new team along with an associated API key", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Team.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) //public Response createTeam(String jsonRequest) { @@ -142,14 +151,14 @@ public Response createTeam(Team jsonTeam) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a team's fields including", - response = Team.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Updates a team's fields including", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Team.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response updateTeam(Team jsonTeam) { @@ -174,14 +183,14 @@ public Response updateTeam(Team jsonTeam) { @DELETE @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a team", - code = 204, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Deletes a team", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteTeam(Team jsonTeam) { @@ -201,19 +210,18 @@ public Response deleteTeam(Team jsonTeam) { @PUT @Path("/{uuid}/key") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Generates an API key and returns its value", - response = ApiKey.class, - code = 201, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Generates an API key and returns its value", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The team could not be found") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ApiKey.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response generateApiKey( - @ApiParam(value = "The UUID of the team to generate a key for", format = "uuid", required = true) + @Parameter(description = "The UUID of the team to generate a key for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, uuid); @@ -229,18 +237,18 @@ public Response generateApiKey( @POST @Path("/key/{apikey}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Regenerates an API key by removing the specified key, generating a new one and returning its value", - response = ApiKey.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Regenerates an API key by removing the specified key, generating a new one and returning its value", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The API key could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ApiKey.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The API key could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response regenerateApiKey( - @ApiParam(value = "The API key to regenerate", required = true) + @Parameter(description = "The API key to regenerate", required = true) @PathParam("apikey") String apikey) { try (QueryManager qm = new QueryManager()) { ApiKey apiKey = qm.getApiKey(apikey); @@ -257,14 +265,14 @@ public Response regenerateApiKey( @Path("/key/{key}/comment") @Consumes(MediaType.TEXT_PLAIN) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates an API key's comment", - response = ApiKey.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Updates an API key's comment", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The API key could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ApiKey.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The API key could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response updateApiKeyComment(@PathParam("key") final String key, @@ -289,18 +297,18 @@ public Response updateApiKeyComment(@PathParam("key") final String key, @DELETE @Path("/key/{apikey}") - @ApiOperation( - value = "Deletes the specified API key", - code = 204, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Deletes the specified API key", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The API key could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The API key could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteApiKey( - @ApiParam(value = "The API key to delete", required = true) + @Parameter(description = "The API key to delete", required = true) @PathParam("apikey") String apikey) { try (QueryManager qm = new QueryManager()) { final ApiKey apiKey = qm.getApiKey(apikey); @@ -316,14 +324,13 @@ public Response deleteApiKey( @GET @Path("self") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns information about the current team.", - response = TeamSelfResponse.class - ) + @Operation( + summary = "Returns information about the current team.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 400, message = "Invalid API key supplied"), - @ApiResponse(code = 404, message = "No Team for the given API key found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = TeamSelfResponse.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "400", description = "Invalid API key supplied"), + @ApiResponse(responseCode = "404", description = "No Team for the given API key found") }) public Response getSelf() { if (Config.getInstance().getPropertyAsBoolean(Config.AlpineKey.ENFORCE_AUTHENTICATION)) { diff --git a/src/main/java/org/dependencytrack/resources/v1/UserResource.java b/src/main/java/org/dependencytrack/resources/v1/UserResource.java index 5b16539ba0..43712307b3 100644 --- a/src/main/java/org/dependencytrack/resources/v1/UserResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/UserResource.java @@ -37,13 +37,17 @@ import alpine.server.auth.PasswordService; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.IdentifiableObject; @@ -74,7 +78,11 @@ * @since 3.0.0 */ @Path("/v1/user") -@Api(value = "user", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "user") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class UserResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(UserResource.class); @@ -83,14 +91,13 @@ public class UserResource extends AlpineResource { @Path("login") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.TEXT_PLAIN) - @ApiOperation( - value = "Assert login credentials", - notes = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.", - response = String.class - ) + @Operation( + summary = "Assert login credentials", + description = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Forbidden") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Forbidden") }) @AuthenticationNotRequired public Response validateCredentials(@FormParam("username") String username, @FormParam("password") String password) { @@ -121,18 +128,17 @@ public Response validateCredentials(@FormParam("username") String username, @For @Path("oidc/login") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.TEXT_PLAIN) - @ApiOperation( - value = "Login with OpenID Connect", - notes = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.", - response = String.class - ) + @Operation( + summary = "Login with OpenID Connect", + description = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "No Content"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Forbidden") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "204", description = "No Content"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Forbidden") }) @AuthenticationNotRequired - public Response validateOidcAccessToken(@ApiParam(value = "An OAuth2 access token", required = true) + public Response validateOidcAccessToken(@Parameter(description = "An OAuth2 access token", required = true) @FormParam("idToken") final String idToken, @FormParam("accessToken") final String accessToken) { final OidcAuthenticationService authService = new OidcAuthenticationService(idToken, accessToken); @@ -164,14 +170,13 @@ public Response validateOidcAccessToken(@ApiParam(value = "An OAuth2 access toke @Path("forceChangePassword") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.TEXT_PLAIN) - @ApiOperation( - value = "Asserts login credentials and upon successful authentication, verifies passwords match and changes users password", - notes = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.", - response = String.class - ) + @Operation( + summary = "Asserts login credentials and upon successful authentication, verifies passwords match and changes users password", + description = "Upon a successful login, a JSON Web Token will be returned in the response body. This functionality requires authentication to be enabled.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Forbidden") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Forbidden") }) @AuthenticationNotRequired public Response forceChangePassword(@FormParam("username") String username, @FormParam("password") String password, @@ -223,15 +228,17 @@ public Response forceChangePassword(@FormParam("username") String username, @For @GET @Path("managed") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all managed users", - response = ManagedUser.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of managed users"), - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Returns a list of all managed users", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of managed users", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ManagedUser.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getManagedUsers() { @@ -245,15 +252,17 @@ public Response getManagedUsers() { @GET @Path("ldap") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all LDAP users", - response = LdapUser.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of LDAP users"), - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Returns a list of all LDAP users", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of LDAP users", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = LdapUser.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getLdapUsers() { @@ -270,15 +279,17 @@ public Response getLdapUsers() { @GET @Path("oidc") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all OIDC users", - response = OidcUser.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of OIDC users"), - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Returns a list of all OIDC users", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of OIDC users", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = OidcUser.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response getOidcUsers() { @@ -292,12 +303,10 @@ public Response getOidcUsers() { @GET @Path("self") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns information about the current logged in user.", - response = UserPrincipal.class - ) + @Operation(summary = "Returns information about the current logged in user.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UserPrincipal.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response getSelf() { if (Config.getInstance().getPropertyAsBoolean(Config.AlpineKey.ENFORCE_AUTHENTICATION)) { @@ -322,13 +331,12 @@ public Response getSelf() { @POST @Path("self") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates information about the current logged in user.", - response = UserPrincipal.class - ) + @Operation( + summary = "Updates information about the current logged in user.") @ApiResponses(value = { - @ApiResponse(code = 400, message = "An invalid payload was submitted or the user is not a managed user."), - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ManagedUser.class))), + @ApiResponse(responseCode = "400", description = "An invalid payload was submitted or the user is not a managed user."), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) public Response updateSelf(ManagedUser jsonUser) { if (Config.getInstance().getPropertyAsBoolean(Config.AlpineKey.ENFORCE_AUTHENTICATION)) { @@ -371,16 +379,15 @@ public Response updateSelf(ManagedUser jsonUser) { @Path("ldap") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new user that references an existing LDAP object.", - response = LdapUser.class, - code = 201, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Creates a new user that references an existing LDAP object.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Username cannot be null or blank."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A user with the same username already exists. Cannot create new user") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = LdapUser.class))), + @ApiResponse(responseCode = "400", description = "Username cannot be null or blank."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A user with the same username already exists. Cannot create new user") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response createLdapUser(LdapUser jsonUser) { @@ -410,14 +417,14 @@ public Response createLdapUser(LdapUser jsonUser) { @Path("ldap") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a user.", - code = 204, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Deletes a user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteLdapUser(LdapUser jsonUser) { @@ -445,16 +452,15 @@ public Response deleteLdapUser(LdapUser jsonUser) { @Path("managed") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new user.", - response = ManagedUser.class, - code = 201, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Creates a new user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Missing required field"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A user with the same username already exists. Cannot create new user") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ManagedUser.class))), + @ApiResponse(responseCode = "400", description = "Missing required field"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A user with the same username already exists. Cannot create new user") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response createManagedUser(ManagedUser jsonUser) { @@ -500,15 +506,15 @@ public Response createManagedUser(ManagedUser jsonUser) { @Path("managed") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates a managed user.", - response = ManagedUser.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Updates a managed user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Missing required field"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = ManagedUser.class))), + @ApiResponse(responseCode = "400", description = "Missing required field"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response updateManagedUser(ManagedUser jsonUser) { @@ -543,14 +549,14 @@ public Response updateManagedUser(ManagedUser jsonUser) { @Path("managed") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a user.", - code = 204, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Deletes a user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteManagedUser(ManagedUser jsonUser) { @@ -578,16 +584,15 @@ public Response deleteManagedUser(ManagedUser jsonUser) { @Path("oidc") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new user that references an existing OpenID Connect user.", - response = OidcUser.class, - code = 201, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Creates a new user that references an existing OpenID Connect user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Username cannot be null or blank."), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A user with the same username already exists. Cannot create new user") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = OidcUser.class))), + @ApiResponse(responseCode = "400", description = "Username cannot be null or blank."), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A user with the same username already exists. Cannot create new user") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response createOidcUser(final OidcUser jsonUser) { @@ -617,14 +622,14 @@ public Response createOidcUser(final OidcUser jsonUser) { @Path("oidc") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes an OpenID Connect user.", - code = 204, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Deletes an OpenID Connect user.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user could not be found") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response deleteOidcUser(final OidcUser jsonUser) { @@ -652,21 +657,21 @@ public Response deleteOidcUser(final OidcUser jsonUser) { @Path("/{username}/membership") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Adds the username to the specified team.", - response = UserPrincipal.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Adds the username to the specified team.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The user is already a member of the specified team"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user or team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UserPrincipal.class))), + @ApiResponse(responseCode = "304", description = "The user is already a member of the specified team"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user or team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response addTeamToUser( - @ApiParam(value = "A valid username", required = true) + @Parameter(description = "A valid username", required = true) @PathParam("username") String username, - @ApiParam(value = "The UUID of the team to associate username with", required = true) + @Parameter(description = "The UUID of the team to associate username with", required = true) IdentifiableObject identifiableObject) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, identifiableObject.getUuid()); @@ -692,21 +697,21 @@ public Response addTeamToUser( @Path("/{username}/membership") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes the username from the specified team.", - response = UserPrincipal.class, - notes = "

        Requires permission ACCESS_MANAGEMENT

        " + @Operation( + summary = "Removes the username from the specified team.", + description = "

        Requires permission ACCESS_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 304, message = "The user was not a member of the specified team"), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The user or team could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UserPrincipal.class))), + @ApiResponse(responseCode = "304", description = "The user was not a member of the specified team"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The user or team could not be found") }) @PermissionRequired(Permissions.Constants.ACCESS_MANAGEMENT) public Response removeTeamFromUser( - @ApiParam(value = "A valid username", required = true) + @Parameter(description = "A valid username", required = true) @PathParam("username") String username, - @ApiParam(value = "The UUID of the team to un-associate username from", required = true) + @Parameter(description = "The UUID of the team to un-associate username from", required = true) IdentifiableObject identifiableObject) { try (QueryManager qm = new QueryManager()) { final Team team = qm.getObjectByUuid(Team.class, identifiableObject.getUuid()); diff --git a/src/main/java/org/dependencytrack/resources/v1/VexResource.java b/src/main/java/org/dependencytrack/resources/v1/VexResource.java index 66bd305b50..80d69db6b2 100644 --- a/src/main/java/org/dependencytrack/resources/v1/VexResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/VexResource.java @@ -22,12 +22,15 @@ import alpine.event.framework.Event; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.BOMInputStream; import org.apache.commons.lang3.StringUtils; @@ -40,6 +43,8 @@ import org.dependencytrack.parser.cyclonedx.CycloneDXExporter; import org.dependencytrack.persistence.QueryManager; import org.dependencytrack.resources.v1.problems.InvalidBomProblemDetails; +import org.dependencytrack.resources.v1.problems.ProblemDetails; +import org.dependencytrack.resources.v1.vo.BomUploadResponse; import org.dependencytrack.resources.v1.vo.VexSubmitRequest; import org.glassfish.jersey.media.multipart.BodyPartEntity; import org.glassfish.jersey.media.multipart.FormDataBodyPart; @@ -69,7 +74,11 @@ * @since 4.5.0 */ @Path("/v1/vex") -@Api(value = "vex", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "vex") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class VexResource extends AlpineResource { private static final Logger LOGGER = Logger.getLogger(VexResource.class); @@ -77,21 +86,21 @@ public class VexResource extends AlpineResource { @GET @Path("/cyclonedx/project/{uuid}") @Produces({CycloneDxMediaType.APPLICATION_CYCLONEDX_JSON, MediaType.APPLICATION_OCTET_STREAM}) - @ApiOperation( - value = "Returns a VEX for a project in CycloneDX format", - response = String.class, - notes = "

        Requires permission VULNERABILITY_ANALYSIS

        " + @Operation( + summary = "Returns a VEX for a project in CycloneDX format", + description = "

        Requires permission VULNERABILITY_ANALYSIS

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_ANALYSIS) public Response exportProjectAsCycloneDx ( - @ApiParam(value = "The UUID of the project to export", format = "uuid", required = true) + @Parameter(description = "The UUID of the project to export", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Force the resulting VEX to be downloaded as a file (defaults to 'false')") + @Parameter(description = "Force the resulting VEX to be downloaded as a file (defaults to 'false')") @QueryParam("download") boolean download) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -122,9 +131,9 @@ public Response exportProjectAsCycloneDx ( @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Upload a supported VEX document", - notes = """ + @Operation( + summary = "Upload a supported VEX document", + description = """

        Expects CycloneDX and a valid project UUID. If a UUID is not specified, then the projectName and projectVersion must be specified. @@ -142,10 +151,18 @@ public Response exportProjectAsCycloneDx (

        Requires permission VULNERABILITY_ANALYSIS

        """ ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid VEX", response = InvalidBomProblemDetails.class), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))), + @ApiResponse( + responseCode = "400", + description = "Invalid VEX", + content = @Content( + schema = @Schema(implementation = InvalidBomProblemDetails.class), + mediaType = ProblemDetails.MEDIA_TYPE_JSON + ) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_ANALYSIS) public Response uploadVex(VexSubmitRequest request) { @@ -175,9 +192,9 @@ public Response uploadVex(VexSubmitRequest request) { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Upload a supported VEX document", - notes = """ + @Operation( + summary = "Upload a supported VEX document", + description = """

        Expects CycloneDX and a valid project UUID. If a UUID is not specified, then the projectName and projectVersion must be specified. @@ -190,16 +207,24 @@ public Response uploadVex(VexSubmitRequest request) {

        Requires permission VULNERABILITY_ANALYSIS

        """ ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid VEX", response = InvalidBomProblemDetails.class), - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))), + @ApiResponse( + responseCode = "400", + description = "Invalid VEX", + content = @Content( + schema = @Schema(implementation = InvalidBomProblemDetails.class), + mediaType = ProblemDetails.MEDIA_TYPE_JSON + ) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_ANALYSIS) public Response uploadVex(@FormDataParam("project") String projectUuid, @FormDataParam("projectName") String projectName, @FormDataParam("projectVersion") String projectVersion, - @ApiParam(type = "string") @FormDataParam("vex") final List artifactParts) { + @Parameter(schema = @Schema(type = "string")) @FormDataParam("vex") final List artifactParts) { if (projectUuid != null) { try (QueryManager qm = new QueryManager()) { final Project project = qm.getObjectByUuid(Project.class, projectUuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/ViolationAnalysisResource.java b/src/main/java/org/dependencytrack/resources/v1/ViolationAnalysisResource.java index 28732cb172..e43e369191 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ViolationAnalysisResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ViolationAnalysisResource.java @@ -26,14 +26,18 @@ import alpine.model.UserPrincipal; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.commons.lang3.StringUtils; import org.dependencytrack.auth.Permissions; +import org.dependencytrack.model.Analysis; import org.dependencytrack.model.Component; import org.dependencytrack.model.PolicyViolation; import org.dependencytrack.model.ViolationAnalysis; @@ -60,24 +64,28 @@ * @since 4.0.0 */ @Path("/v1/violation/analysis") -@Api(value = "violationanalysis", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "violationanalysis") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class ViolationAnalysisResource extends AlpineResource { @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Retrieves a violation analysis trail", - response = ViolationAnalysis.class, - notes = "

        Requires permission VIEW_POLICY_VIOLATION

        " + @Operation( + summary = "Retrieves a violation analysis trail", + description = "

        Requires permission VIEW_POLICY_VIOLATION

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The component or policy violation could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The component or policy violation could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_POLICY_VIOLATION) - public Response retrieveAnalysis(@ApiParam(value = "The UUID of the component", format = "uuid", required = true) + public Response retrieveAnalysis(@Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @QueryParam("component") @ValidUuid String componentUuid, - @ApiParam(value = "The UUID of the policy violation", format = "uuid", required = true) + @Parameter(description = "The UUID of the policy violation", schema = @Schema(type = "string", format = "uuid"), required = true) @QueryParam("policyViolation") @ValidUuid String violationUuid) { failOnValidationError( new ValidationTask(RegexSequence.Pattern.UUID, componentUuid, "Component is not a valid UUID"), @@ -100,14 +108,14 @@ public Response retrieveAnalysis(@ApiParam(value = "The UUID of the component", @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Records a violation analysis decision", - response = ViolationAnalysis.class, - notes = "

        Requires permission POLICY_VIOLATION_ANALYSIS

        " + @Operation( + summary = "Records a violation analysis decision", + description = "

        Requires permission POLICY_VIOLATION_ANALYSIS

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The component or policy violation could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The component or policy violation could not be found") }) @PermissionRequired(Permissions.Constants.POLICY_VIOLATION_ANALYSIS) public Response updateAnalysis(ViolationAnalysisRequest request) { diff --git a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java index 091c77e41e..e76a476e15 100644 --- a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java @@ -21,13 +21,17 @@ import alpine.persistence.PaginatedResult; import alpine.server.auth.PermissionRequired; import alpine.server.resources.AlpineResource; -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 io.swagger.annotations.Authorization; -import io.swagger.annotations.ResponseHeader; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; import org.dependencytrack.auth.Permissions; import org.dependencytrack.model.AffectedVersionAttribution; import org.dependencytrack.model.Component; @@ -71,29 +75,35 @@ * @since 3.0.0 */ @Path("/v1/vulnerability") -@Api(value = "vulnerability", authorizations = @Authorization(value = "X-Api-Key")) +@Tag(name = "vulnerability") +@SecurityRequirements({ + @SecurityRequirement(name = "ApiKeyAuth"), + @SecurityRequirement(name = "BearerAuth") +}) public class VulnerabilityResource extends AlpineResource { @GET @Path("/component/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all vulnerabilities for a specific component", - response = Vulnerability.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of vulnerabilities"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all vulnerabilities for a specific component", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The component could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of vulnerabilities", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Vulnerability.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The component could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getVulnerabilitiesByComponent(@ApiParam(value = "The UUID of the component to retrieve vulnerabilities for", format = "uuid", required = true) + public Response getVulnerabilitiesByComponent(@Parameter(description = "The UUID of the component to retrieve vulnerabilities for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes suppressed vulnerabilities") + @Parameter(description = "Optionally includes suppressed vulnerabilities") @QueryParam("suppressed") boolean suppressed) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Component component = qm.getObjectByUuid(Component.class, uuid); @@ -113,22 +123,24 @@ public Response getVulnerabilitiesByComponent(@ApiParam(value = "The UUID of the @GET @Path("/project/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all vulnerabilities for a specific project", - response = Vulnerability.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of vulnerabilities"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all vulnerabilities for a specific project", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified project is forbidden"), - @ApiResponse(code = 404, message = "The project could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of vulnerabilities", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Vulnerability.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"), + @ApiResponse(responseCode = "404", description = "The project could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) - public Response getVulnerabilitiesByProject(@ApiParam(value = "The UUID of the project to retrieve vulnerabilities for", format = "uuid", required = true) + public Response getVulnerabilitiesByProject(@Parameter(description = "The UUID of the project to retrieve vulnerabilities for", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "Optionally includes suppressed vulnerabilities") + @Parameter(description = "Optionally includes suppressed vulnerabilities") @QueryParam("suppressed") boolean suppressed) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Project project = qm.getObjectByUuid(Project.class, uuid); @@ -149,17 +161,17 @@ public Response getVulnerabilitiesByProject(@ApiParam(value = "The UUID of the p @GET @Path("/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific vulnerability", - response = Vulnerability.class, - notes = "

        Requires permission VULNERABILITY_MANAGEMENT

        " + @Operation( + summary = "Returns a specific vulnerability", + description = "

        Requires permission VULNERABILITY_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The vulnerability could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Vulnerability.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The vulnerability could not be found") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_MANAGEMENT) - public Response getVulnerabilityByUuid(@ApiParam(value = "The UUID of the vulnerability", format = "uuid", required = true) + public Response getVulnerabilityByUuid(@Parameter(description = "The UUID of the vulnerability", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); @@ -174,14 +186,14 @@ public Response getVulnerabilityByUuid(@ApiParam(value = "The UUID of the vulner @GET @Path("/source/{source}/vuln/{vuln}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a specific vulnerability", - response = Vulnerability.class, - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a specific vulnerability", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The vulnerability could not be found") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Vulnerability.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The vulnerability could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getVulnerabilityByVulnId(@PathParam("source") String source, @@ -207,21 +219,23 @@ public Response getVulnerabilityByVulnId(@PathParam("source") String source, @GET @Path("/source/{source}/vuln/{vuln}/projects") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all projects affected by a specific vulnerability", - response = Project.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of projects"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all projects affected by a specific vulnerability", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The vulnerability could not be found") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The vulnerability could not be found") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getAffectedProject(@PathParam("source") String source, @PathParam("vuln") String vuln, - @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @Parameter(description = "Optionally excludes inactive projects from being returned", required = false) @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Vulnerability vulnerability = qm.getVulnerabilityByVulnId(source, vuln); @@ -242,16 +256,18 @@ public Response getAffectedProject(@PathParam("source") String source, @GET @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Returns a list of all vulnerabilities", - response = Vulnerability.class, - responseContainer = "List", - responseHeaders = @ResponseHeader(name = TOTAL_COUNT_HEADER, response = Long.class, description = "The total number of vulnerabilities"), - notes = "

        Requires permission VIEW_PORTFOLIO

        " + @Operation( + summary = "Returns a list of all vulnerabilities", + description = "

        Requires permission VIEW_PORTFOLIO

        " ) @PaginatedApi @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse( + responseCode = "200", + headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of vulnerabilities", schema = @Schema(format = "integer")), + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Vulnerability.class))) + ), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getAllVulnerabilities() { @@ -264,15 +280,14 @@ public Response getAllVulnerabilities() { @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Creates a new vulnerability", - response = Vulnerability.class, - code = 201, - notes = "

        Requires permission VULNERABILITY_MANAGEMENT

        " + @Operation( + summary = "Creates a new vulnerability", + description = "

        Requires permission VULNERABILITY_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 409, message = "A vulnerability with the specified vulnId already exists") + @ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = Vulnerability.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "A vulnerability with the specified vulnId already exists") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_MANAGEMENT) public Response createVulnerability(Vulnerability jsonVulnerability) { @@ -337,15 +352,15 @@ public Response createVulnerability(Vulnerability jsonVulnerability) { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Updates an internal vulnerability", - response = Project.class, - notes = "

        Requires permission VULNERABILITY_MANAGEMENT

        " + @Operation( + summary = "Updates an internal vulnerability", + description = "

        Requires permission VULNERABILITY_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 404, message = "The vulnerability could not be found"), - @ApiResponse(code = 406, message = "The vulnId may not be changed") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Vulnerability.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "404", description = "The vulnerability could not be found"), + @ApiResponse(responseCode = "406", description = "The vulnId may not be changed") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_MANAGEMENT) public Response updateVulnerability(Vulnerability jsonVuln) { @@ -413,20 +428,20 @@ public Response updateVulnerability(Vulnerability jsonVuln) { @Path("/{uuid}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Deletes a vulnerability", - code = 204, - notes = "

        Requires permission VULNERABILITY_MANAGEMENT

        " + @Operation( + summary = "Deletes a vulnerability", + description = "

        Requires permission VULNERABILITY_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified vulnerability is forbidden"), - @ApiResponse(code = 404, message = "The UUID of the vulnerability could not be found"), - @ApiResponse(code = 412, message = "Portfolio components or services are affected by this vulnerability. Unable to delete.") + @ApiResponse(responseCode = "204"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified vulnerability is forbidden"), + @ApiResponse(responseCode = "404", description = "The UUID of the vulnerability could not be found"), + @ApiResponse(responseCode = "412", description = "Portfolio components or services are affected by this vulnerability. Unable to delete.") }) @PermissionRequired(Permissions.Constants.VULNERABILITY_MANAGEMENT) public Response deleteVulnerability( - @ApiParam(value = "The UUID of the vulnerability to delete", format = "uuid", required = true) + @Parameter(description = "The UUID of the vulnerability to delete", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); @@ -451,13 +466,13 @@ public Response deleteVulnerability( @GET @Path("/vulnId") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Generates an internal vulnerability identifier", - response = String.class, - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Generates an internal vulnerability identifier", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized") + @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))), + @ApiResponse(responseCode = "401", description = "Unauthorized") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) public Response generateInternalVulnerabilityIdentifier() { @@ -509,21 +524,22 @@ public void recalculateScoresAndSeverityFromVectors(Vulnerability vuln) throws M @Path("/source/{source}/vuln/{vulnId}/component/{component}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Assigns a vulnerability to a component", - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Assigns a vulnerability to a component", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The vulnerability or component could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The vulnerability or component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response assignVulnerability(@ApiParam(value = "The vulnerability source", required = true) + public Response assignVulnerability(@Parameter(description = "The vulnerability source", required = true) @PathParam("source") String source, - @ApiParam(value = "The vulnId", required = true) + @Parameter(description = "The vulnId", required = true) @PathParam("vulnId") String vulnId, - @ApiParam(value = "The UUID of the component", format = "uuid", required = true) + @Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("component") @ValidUuid String componentUuid) { try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getVulnerabilityByVulnId(source, vulnId); @@ -548,19 +564,20 @@ public Response assignVulnerability(@ApiParam(value = "The vulnerability source" @Path("/{uuid}/component/{component}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Assigns a vulnerability to a component", - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Assigns a vulnerability to a component", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The vulnerability or component could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The vulnerability or component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response assignVulnerability(@ApiParam(value = "The UUID of the vulnerability", format = "uuid", required = true) + public Response assignVulnerability(@Parameter(description = "The UUID of the vulnerability", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The UUID of the component", format = "uuid", required = true) + @Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("component") @ValidUuid String componentUuid) { try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); @@ -585,21 +602,22 @@ public Response assignVulnerability(@ApiParam(value = "The UUID of the vulnerabi @Path("/source/{source}/vuln/{vulnId}/component/{component}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes assignment of a vulnerability from a component", - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Removes assignment of a vulnerability from a component", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The vulnerability or component could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The vulnerability or component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response unassignVulnerability(@ApiParam(value = "The vulnerability source", required = true) + public Response unassignVulnerability(@Parameter(description = "The vulnerability source", required = true) @PathParam("source") String source, - @ApiParam(value = "The vulnId", required = true) + @Parameter(description = "The vulnId", required = true) @PathParam("vulnId") String vulnId, - @ApiParam(value = "The UUID of the component", format = "uuid", required = true) + @Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("component") @ValidUuid String componentUuid) { try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getVulnerabilityByVulnId(source, vulnId); @@ -624,19 +642,20 @@ public Response unassignVulnerability(@ApiParam(value = "The vulnerability sourc @Path("/{uuid}/component/{component}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Removes assignment of a vulnerability from a component", - notes = "

        Requires permission PORTFOLIO_MANAGEMENT

        " + @Operation( + summary = "Removes assignment of a vulnerability from a component", + description = "

        Requires permission PORTFOLIO_MANAGEMENT

        " ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "Unauthorized"), - @ApiResponse(code = 403, message = "Access to the specified component is forbidden"), - @ApiResponse(code = 404, message = "The vulnerability or component could not be found") + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"), + @ApiResponse(responseCode = "404", description = "The vulnerability or component could not be found") }) @PermissionRequired(Permissions.Constants.PORTFOLIO_MANAGEMENT) - public Response unassignVulnerability(@ApiParam(value = "The UUID of the vulnerability", format = "uuid", required = true) + public Response unassignVulnerability(@Parameter(description = "The UUID of the vulnerability", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("uuid") @ValidUuid String uuid, - @ApiParam(value = "The UUID of the component", format = "uuid", required = true) + @Parameter(description = "The UUID of the component", schema = @Schema(type = "string", format = "uuid"), required = true) @PathParam("component") @ValidUuid String componentUuid) { try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); diff --git a/src/main/java/org/dependencytrack/resources/v1/openapi/PaginatedApi.java b/src/main/java/org/dependencytrack/resources/v1/openapi/PaginatedApi.java index 64ea233efc..ca1fa37419 100644 --- a/src/main/java/org/dependencytrack/resources/v1/openapi/PaginatedApi.java +++ b/src/main/java/org/dependencytrack/resources/v1/openapi/PaginatedApi.java @@ -18,8 +18,10 @@ */ package org.dependencytrack.resources.v1.openapi; -import io.swagger.annotations.ApiImplicitParam; -import io.swagger.annotations.ApiImplicitParams; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -33,45 +35,39 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -@ApiImplicitParams({ - @ApiImplicitParam( +@Parameters({ + @Parameter( name = "pageNumber", - dataType = "int", - paramType = "query", - defaultValue = "1", - value = "The page to return. To be used in conjunction with pageSize." + in = ParameterIn.QUERY, + schema = @Schema(defaultValue = "1"), + description = "The page to return. To be used in conjunction with pageSize." ), - @ApiImplicitParam( + @Parameter( name = "pageSize", - dataType = "int", - paramType = "query", - defaultValue = "100", - value = "Number of elements to return per page. To be used in conjunction with pageNumber." + in = ParameterIn.QUERY, + schema = @Schema(defaultValue = "100"), + description = "Number of elements to return per page. To be used in conjunction with pageNumber." ), - @ApiImplicitParam( + @Parameter( name = "offset", - dataType = "int", - paramType = "query", - value = "Offset to start returning elements from. To be used in conjunction with limit." + in = ParameterIn.QUERY, + description = "Offset to start returning elements from. To be used in conjunction with limit." ), - @ApiImplicitParam( + @Parameter( name = "limit", - dataType = "int", - paramType = "query", - value = "Number of elements to return per page. To be used in conjunction with offset." + in = ParameterIn.QUERY, + description = "Number of elements to return per page. To be used in conjunction with offset." ), - @ApiImplicitParam( + @Parameter( name = "sortName", - dataType = "string", - paramType = "query", - value = "Name of the resource field to sort on." + in = ParameterIn.QUERY, + description = "Name of the resource field to sort on." ), - @ApiImplicitParam( + @Parameter( name = "sortOrder", - dataType = "string", - paramType = "query", - allowableValues = "asc, desc", - value = "Ordering of items when sorting with sortName." + in = ParameterIn.QUERY, + schema = @Schema(allowableValues = "asc, desc"), + description = "Ordering of items when sorting with sortName." ) }) public @interface PaginatedApi { diff --git a/src/main/java/org/dependencytrack/resources/v1/problems/InvalidBomProblemDetails.java b/src/main/java/org/dependencytrack/resources/v1/problems/InvalidBomProblemDetails.java index f82b35a5d3..d069ae98e0 100644 --- a/src/main/java/org/dependencytrack/resources/v1/problems/InvalidBomProblemDetails.java +++ b/src/main/java/org/dependencytrack/resources/v1/problems/InvalidBomProblemDetails.java @@ -18,7 +18,7 @@ */ package org.dependencytrack.resources.v1.problems; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; @@ -27,7 +27,7 @@ */ public class InvalidBomProblemDetails extends ProblemDetails { - @ApiModelProperty(value = "Errors identified during schema validation") + @Schema(description = "Errors identified during schema validation") private List errors; public List getErrors() { diff --git a/src/main/java/org/dependencytrack/resources/v1/problems/ProblemDetails.java b/src/main/java/org/dependencytrack/resources/v1/problems/ProblemDetails.java index 083ec57d48..f5c1391965 100644 --- a/src/main/java/org/dependencytrack/resources/v1/problems/ProblemDetails.java +++ b/src/main/java/org/dependencytrack/resources/v1/problems/ProblemDetails.java @@ -19,8 +19,7 @@ package org.dependencytrack.resources.v1.problems; import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.net.URI; @@ -28,7 +27,7 @@ * @see RFC 9457 * @since 4.11.0 */ -@ApiModel( +@Schema( description = "An RFC 9457 problem object", subTypes = InvalidBomProblemDetails.class ) @@ -37,35 +36,35 @@ public class ProblemDetails { public static final String MEDIA_TYPE_JSON = "application/problem+json"; - @ApiModelProperty( - value = "A URI reference that identifies the problem type", + @Schema( + description = "A URI reference that identifies the problem type", example = "https://api.example.org/foo/bar/example-problem" ) private URI type; - @ApiModelProperty( - value = "HTTP status code generated by the origin server for this occurrence of the problem", + @Schema( + description = "HTTP status code generated by the origin server for this occurrence of the problem", example = "400", required = true ) private Integer status; - @ApiModelProperty( - value = "Short, human-readable summary of the problem type", + @Schema( + description = "Short, human-readable summary of the problem type", example = "Example title", required = true ) private String title; - @ApiModelProperty( - value = "Human-readable explanation specific to this occurrence of the problem", + @Schema( + description = "Human-readable explanation specific to this occurrence of the problem", example = "Example detail", required = true ) private String detail; - @ApiModelProperty( - value = "Reference URI that identifies the specific occurrence of the problem", + @Schema( + description = "Reference URI that identifies the specific occurrence of the problem", example = "https://api.example.org/foo/bar/example-instance" ) private URI instance; diff --git a/src/main/java/org/dependencytrack/resources/v1/vo/BomSubmitRequest.java b/src/main/java/org/dependencytrack/resources/v1/vo/BomSubmitRequest.java index 17830597f9..8e7f3a1140 100644 --- a/src/main/java/org/dependencytrack/resources/v1/vo/BomSubmitRequest.java +++ b/src/main/java/org/dependencytrack/resources/v1/vo/BomSubmitRequest.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @@ -95,32 +95,32 @@ public BomSubmitRequest(@JsonProperty(value = "project") String project, this.bom = bom; } - @ApiModelProperty(example = "38640b33-4ba9-4733-bdab-cbfc40c6f8aa") + @Schema(example = "38640b33-4ba9-4733-bdab-cbfc40c6f8aa") public String getProject() { return project; } - @ApiModelProperty(example = "Example Application") + @Schema(example = "Example Application") public String getProjectName() { return projectName; } - @ApiModelProperty(example = "1.0.0") + @Schema(example = "1.0.0") public String getProjectVersion() { return projectVersion; } - @ApiModelProperty(example = "5341f53c-611b-4388-9d9c-731026dc5eec") + @Schema(example = "5341f53c-611b-4388-9d9c-731026dc5eec") public String getParentUUID() { return parentUUID; } - @ApiModelProperty(example = "Example Application Parent") + @Schema(example = "Example Application Parent") public String getParentName() { return parentName; } - @ApiModelProperty(example = "1.0.0") + @Schema(example = "1.0.0") public String getParentVersion() { return parentVersion; } @@ -129,8 +129,8 @@ public boolean isAutoCreate() { return autoCreate; } - @ApiModelProperty( - value = "Base64 encoded BOM", + @Schema( + description = "Base64 encoded BOM", required = true, example = """ ewogICJib21Gb3JtYXQiOiAiQ3ljbG9uZURYIiwKICAic3BlY1ZlcnNpb24iOiAi\ diff --git a/src/main/java/org/dependencytrack/resources/v1/vo/BomUploadResponse.java b/src/main/java/org/dependencytrack/resources/v1/vo/BomUploadResponse.java index 992e287b8f..2c0c8a8888 100644 --- a/src/main/java/org/dependencytrack/resources/v1/vo/BomUploadResponse.java +++ b/src/main/java/org/dependencytrack/resources/v1/vo/BomUploadResponse.java @@ -18,16 +18,16 @@ */ package org.dependencytrack.resources.v1.vo; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.UUID; -import io.swagger.annotations.ApiModelProperty; - public class BomUploadResponse implements Serializable { private static final long serialVersionUID = -7592436786586686865L; - @ApiModelProperty(required = true, value = "Token used to check task progress") + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Token used to check task progress") private UUID token; public void setToken(UUID token) { diff --git a/src/main/java/org/dependencytrack/resources/v1/vo/IsTokenBeingProcessedResponse.java b/src/main/java/org/dependencytrack/resources/v1/vo/IsTokenBeingProcessedResponse.java index 08118b983e..4e354c936d 100644 --- a/src/main/java/org/dependencytrack/resources/v1/vo/IsTokenBeingProcessedResponse.java +++ b/src/main/java/org/dependencytrack/resources/v1/vo/IsTokenBeingProcessedResponse.java @@ -18,15 +18,15 @@ */ package org.dependencytrack.resources.v1.vo; -import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; public class IsTokenBeingProcessedResponse implements Serializable { private static final long serialVersionUID = -7592468766586686855L; - @ApiModelProperty(required = true) + @Schema(required = true) private Boolean processing; public void setProcessing(Boolean processing) { diff --git a/src/main/webapp/WEB-INF/openapi-configuration.yaml b/src/main/webapp/WEB-INF/openapi-configuration.yaml new file mode 100644 index 0000000000..107d82f146 --- /dev/null +++ b/src/main/webapp/WEB-INF/openapi-configuration.yaml @@ -0,0 +1,17 @@ +openAPI: + info: + version: "4.12.0" + title: "Dependency-Track REST API" + components: + securitySchemes: + ApiKeyAuth: + name: X-Api-Key + type: apiKey + in: header + BearerAuth: + type: http + scheme: Bearer +prettyPrint: true +resourcePackages: +- alpine.server.resources +- org.dependencytrack.resources \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 4c818c73b6..f5d7b16336 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -113,7 +113,7 @@ alpine.server.AlpineServlet jersey.config.server.provider.packages - io.swagger.jaxrs.listing,alpine.server.filters,alpine.server.resources,org.dependencytrack.resources,org.dependencytrack.filters + alpine.server.filters,alpine.server.resources,org.dependencytrack.resources,org.dependencytrack.filters jersey.config.server.provider.classnames @@ -123,10 +123,6 @@ jersey.config.beanValidation.enableOutputValidationErrorEntity.server true - - swagger.pretty.print - true - 1