diff --git a/build.gradle b/build.gradle index 0d44c8a3..bcfe6a56 100644 --- a/build.gradle +++ b/build.gradle @@ -43,9 +43,9 @@ dependencies { implementation 'com.epam.reportportal:commons-rules' implementation 'com.epam.reportportal:commons-model' } else { - implementation 'com.github.reportportal:commons-dao:3d0fd7a8' - implementation 'com.github.reportportal:commons-rules:01ec4d17' - implementation 'com.github.reportportal:commons-model:232e69a5' + implementation 'com.github.reportportal:commons-dao:9941604' + implementation 'com.github.reportportal:commons-rules:837ccf2' + implementation 'com.github.reportportal:commons-model:94c46aa' } //Fix CVE-2021-41079, CVE-2022-23181, CVE-2021-33037, CVE-2021-30640, CVE-2022-42252 @@ -88,7 +88,7 @@ dependencies { implementation 'org.apache.tika:tika-core' implementation 'javax.inject:javax.inject:1' - implementation 'io.springfox:springfox-swagger2' + implementation 'org.springdoc:springdoc-openapi-ui:1.7.0' implementation 'org.apache.commons:commons-compress:1.21' implementation 'org.cryptacular:cryptacular:1.1.4' // TODO: snakeyaml 2.0 supported by Spring Boot 3 only diff --git a/project-properties.gradle b/project-properties.gradle index 0f1ccb0c..4231dea0 100755 --- a/project-properties.gradle +++ b/project-properties.gradle @@ -4,7 +4,7 @@ project.ext { publishRepo = "https://maven.pkg.github.com/reportportal/service-authorization" dependencyRepos = ["commons-dao", "commons-rules", "commons-model", "commons-bom"] releaseMode = project.hasProperty("releaseMode") - scriptsUrl = commonScriptsUrl + 'java21' //(releaseMode ? '5.10.0' : 'master') + scriptsUrl = commonScriptsUrl + (releaseMode ? '5.10.0' : 'develop') isDebugMode = System.getProperty("DEBUG", "false") == "true" } diff --git a/src/main/java/com/epam/reportportal/auth/config/SpringDocConfiguration.java b/src/main/java/com/epam/reportportal/auth/config/SpringDocConfiguration.java new file mode 100644 index 00000000..aa19a05c --- /dev/null +++ b/src/main/java/com/epam/reportportal/auth/config/SpringDocConfiguration.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023 EPAM Systems + * + * 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. + */ +package com.epam.reportportal.auth.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.tags.Tag; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; +import javax.servlet.ServletContext; +import org.springdoc.core.customizers.OpenApiCustomiser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author Andrei Piankouski + */ +@Configuration +@ComponentScan(basePackages = "com.epam.reportportal.auth") +public class SpringDocConfiguration { + + @Autowired + private ServletContext servletContext; + + @Value("${spring.application.name}") + private String applicationName; + + @Value("${info.build.version}") + private String buildVersion; + + @Bean + public OpenAPI springShopOpenAPI() { + return new OpenAPI() + .info(new Info().title("Report Portal") + .description("Report Portal UAT documentation") + .version(buildVersion) + .contact(new Contact() + .name("Support") + .email("Support Report Portal ") + ) + .license(new License().name("Apache 2.0") + .url("http://www.apache.org/licenses/LICENSE-2.0"))) + .addServersItem(new Server().url("/" + applicationName)); + } + + @Bean + public OpenApiCustomiser sortSchemasAlphabetically() { + return openApi -> { + Map schemas = openApi.getComponents().getSchemas(); + openApi.getComponents().setSchemas(new TreeMap<>(schemas)); + }; + } + + @Bean + public OpenApiCustomiser sortTagsAlphabetically() { + return openApi -> { + List sortedTags = openApi.getTags().stream() + .sorted(Comparator.comparing(Tag::getName)) + .collect(Collectors.toList()); + openApi.setTags(sortedTags); + }; + } +} diff --git a/src/main/java/com/epam/reportportal/auth/config/Swagger2Configuration.java b/src/main/java/com/epam/reportportal/auth/config/Swagger2Configuration.java deleted file mode 100644 index 4a312e54..00000000 --- a/src/main/java/com/epam/reportportal/auth/config/Swagger2Configuration.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * 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. - */ -package com.epam.reportportal.auth.config; - -import com.epam.ta.reportportal.commons.ReportPortalUser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.PathProvider; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.Contact; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.paths.RelativePathProvider; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger.web.UiConfiguration; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -import javax.servlet.ServletContext; -import java.util.Collections; - -import static com.google.common.base.Predicates.not; -import static com.google.common.base.Predicates.or; -import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; - -/** - * @author Pavel Bortnik - */ -@Configuration -@EnableSwagger2 -@ComponentScan(basePackages = "com.epam.reportportal.auth") -public class Swagger2Configuration { - - @Autowired - private ServletContext servletContext; - - @Value("${info.build.version}") - private String buildVersion; - - @Value("${spring.application.name}") - private String applicationName; - - @Bean - public Docket docket() { - ApiInfo rpInfo = new ApiInfo( - "Report Portal", - "Report Portal UAT documentation", - buildVersion, - null, - new Contact("Support", null, "Support EPMC-TST Report Portal "), - "Apache 2.0", - "http://www.apache.org/licenses/LICENSE-2.0", - Collections.emptyList() - ); - - Docket rpDocket = new Docket(DocumentationType.SWAGGER_2).ignoredParameterTypes(ReportPortalUser.class) - .useDefaultResponseMessages(false) - .pathProvider(rpPathProvider()) - /* remove default endpoints from listing */ - .select() - .apis(not(or( - basePackage("org.springframework.boot"), - basePackage("org.springframework.cloud"), - basePackage("org.springframework.security.oauth2.provider.endpoint") - ))) - .build(); - //@formatter:on - - rpDocket.apiInfo(rpInfo); - return rpDocket; - } - - @Bean - public PathProvider rpPathProvider() { - return new RelativePathProvider(servletContext) { - @Override - public String getApplicationBasePath() { - if (super.getApplicationBasePath().contains(applicationName)) { - return super.getApplicationBasePath(); - } - return "/" + applicationName + super.getApplicationBasePath(); - } - }; - } - - @Bean - public UiConfiguration uiConfig() { - return new UiConfiguration(null); - } - -} diff --git a/src/main/java/com/epam/reportportal/auth/endpoint/AuthConfigurationEndpoint.java b/src/main/java/com/epam/reportportal/auth/endpoint/AuthConfigurationEndpoint.java index ce4f7fff..82630775 100644 --- a/src/main/java/com/epam/reportportal/auth/endpoint/AuthConfigurationEndpoint.java +++ b/src/main/java/com/epam/reportportal/auth/endpoint/AuthConfigurationEndpoint.java @@ -25,19 +25,29 @@ import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.integration.auth.AbstractAuthResource; import com.epam.ta.reportportal.ws.model.integration.auth.UpdateAuthRQ; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.beans.PropertyEditorSupport; +import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.beans.PropertyEditorSupport; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/settings/auth") +@Tag(name = "auth-configuration-endpoint", description = "Auth Configuration Endpoint") public class AuthConfigurationEndpoint { private final CreateAuthIntegrationHandler createAuthIntegrationHandler; @@ -63,7 +73,7 @@ public AuthConfigurationEndpoint(CreateAuthIntegrationHandler createAuthIntegrat @Transactional @PostMapping(value = "/{authType}") @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Create new auth integration") + @Operation(summary = "Create new auth integration") public AbstractAuthResource createAuthIntegration(@RequestBody @Valid UpdateAuthRQ request, @AuthenticationPrincipal ReportPortalUser user, @PathVariable AuthIntegrationType authType) { return createAuthIntegrationHandler.createAuthIntegration(authType, request, user); @@ -78,7 +88,7 @@ public AbstractAuthResource createAuthIntegration(@RequestBody @Valid UpdateAuth @Transactional @PutMapping(value = "/{authType}/{integrationId}") @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Update auth integration") + @Operation(summary = "Update auth integration") public AbstractAuthResource updateAuthIntegration(@RequestBody @Valid UpdateAuthRQ request, @AuthenticationPrincipal ReportPortalUser user, @PathVariable AuthIntegrationType authType, @PathVariable Long integrationId) { return createAuthIntegrationHandler.updateAuthIntegration(authType, integrationId, request, user); @@ -93,7 +103,7 @@ public AbstractAuthResource updateAuthIntegration(@RequestBody @Valid UpdateAuth @Transactional(readOnly = true) @GetMapping(value = "/{authType}") @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Retrieves auth settings") + @Operation(summary = "Retrieves auth settings") public AbstractAuthResource getSettings(@PathVariable AuthIntegrationType authType) { return getAuthIntegrationHandler.getIntegrationByType(authType); } @@ -107,7 +117,7 @@ public AbstractAuthResource getSettings(@PathVariable AuthIntegrationType authTy @Transactional @DeleteMapping(value = "/{integrationId}") @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Retrieves auth settings") + @Operation(summary = "Retrieves auth settings") public OperationCompletionRS deleteSettings(@PathVariable Long integrationId) { return deleteAuthIntegrationHandler.deleteAuthIntegrationById(integrationId); } diff --git a/src/main/java/com/epam/reportportal/auth/endpoint/OAuthConfigurationEndpoint.java b/src/main/java/com/epam/reportportal/auth/endpoint/OAuthConfigurationEndpoint.java index 97eb2fbd..b5b08ac4 100644 --- a/src/main/java/com/epam/reportportal/auth/endpoint/OAuthConfigurationEndpoint.java +++ b/src/main/java/com/epam/reportportal/auth/endpoint/OAuthConfigurationEndpoint.java @@ -20,7 +20,8 @@ import com.epam.reportportal.auth.integration.handler.GetAuthIntegrationHandler; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.settings.OAuthRegistrationResource; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; @@ -39,6 +40,7 @@ */ @Controller @RequestMapping("/settings/oauth") +@Tag(name = "o-auth-configuration-endpoint", description = "O Auth Configuration Endpoint") public class OAuthConfigurationEndpoint { private final CreateAuthIntegrationHandler createAuthIntegrationHandler; @@ -65,7 +67,7 @@ public OAuthConfigurationEndpoint(CreateAuthIntegrationHandler createAuthIntegra @RequestMapping(value = "/{authId}", method = { POST, PUT }) @ResponseBody @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Creates/Updates OAuth Integration Settings") + @Operation(summary = "Creates/Updates OAuth Integration Settings") public OAuthRegistrationResource updateOAuthSettings(@PathVariable("authId") String oauthProviderId, @RequestBody @Validated OAuthRegistrationResource clientRegistrationResource) { return createAuthIntegrationHandler.createOrUpdateOauthSettings(oauthProviderId, clientRegistrationResource); @@ -80,7 +82,7 @@ public OAuthRegistrationResource updateOAuthSettings(@PathVariable("authId") Str @RequestMapping(value = "/{authId}", method = { DELETE }) @ResponseBody @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Deletes OAuth Integration Settings") + @Operation(summary = "Deletes OAuth Integration Settings") public OperationCompletionRS deleteOAuthSetting(@PathVariable("authId") String oauthProviderId) { return deleteAuthIntegrationHandler.deleteOauthSettingsById(oauthProviderId); } @@ -93,7 +95,7 @@ public OperationCompletionRS deleteOAuthSetting(@PathVariable("authId") String o @GetMapping @ResponseBody @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Returns OAuth Server Settings") + @Operation(summary = "Returns OAuth Server Settings") public Map getOAuthSettings() { return getAuthIntegrationHandler.getAllOauthIntegrations(); } @@ -107,7 +109,7 @@ public Map getOAuthSettings() { @RequestMapping(value = "/{authId}", method = { GET }) @ResponseBody @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Returns OAuth Server Settings") + @Operation(summary = "Returns OAuth Server Settings") public OAuthRegistrationResource getOAuthSettings(@PathVariable("authId") String oauthProviderId) { return getAuthIntegrationHandler.getOauthIntegrationById(oauthProviderId); } diff --git a/src/main/java/com/epam/reportportal/auth/endpoint/SsoEndpoint.java b/src/main/java/com/epam/reportportal/auth/endpoint/SsoEndpoint.java index d5d70a0f..cbe3677b 100644 --- a/src/main/java/com/epam/reportportal/auth/endpoint/SsoEndpoint.java +++ b/src/main/java/com/epam/reportportal/auth/endpoint/SsoEndpoint.java @@ -17,6 +17,7 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.google.common.collect.ImmutableMap; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.transaction.annotation.Transactional; @@ -36,6 +37,7 @@ */ @RestController @Transactional +@Tag(name = "sso-endpoint", description = "Sso Endpoint") public class SsoEndpoint { @RequestMapping(value = { "/sso/me", "/sso/user" }, method = { GET, POST }) diff --git a/src/main/java/com/epam/reportportal/auth/integration/github/GithubEndpoint.java b/src/main/java/com/epam/reportportal/auth/integration/github/GithubEndpoint.java index ba6d24c6..73a423ab 100644 --- a/src/main/java/com/epam/reportportal/auth/integration/github/GithubEndpoint.java +++ b/src/main/java/com/epam/reportportal/auth/integration/github/GithubEndpoint.java @@ -15,27 +15,28 @@ */ package com.epam.reportportal.auth.integration.github; +import static com.epam.reportportal.auth.integration.github.ExternalOauth2TokenConverter.UPSTREAM_TOKEN; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.io.Serializable; +import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; -import java.io.Serializable; -import java.util.Objects; - -import static com.epam.reportportal.auth.integration.github.ExternalOauth2TokenConverter.UPSTREAM_TOKEN; - /** * GitHUB synchronization endpoint * * @author Andrei Varabyeu */ @RestController +@Tag(name = "github-endpoint", description = "Github Endpoint") public class GithubEndpoint { private final GitHubUserReplicator replicator; @@ -45,7 +46,7 @@ public GithubEndpoint(GitHubUserReplicator replicator) { this.replicator = replicator; } - @ApiOperation(value = "Synchronizes logged-in GitHub user") + @Operation(summary = "Synchronizes logged-in GitHub user") @RequestMapping(value = { "/sso/me/github/synchronize" }, method = RequestMethod.POST) public OperationCompletionRS synchronize(OAuth2Authentication user) { Serializable upstreamToken = user.getOAuth2Request().getExtensions().get(UPSTREAM_TOKEN); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index c010dea0..f5c20493 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -32,11 +32,10 @@ logging: org.hibernate.stat: info org.springframework.web.bind: fatal -springfox: - documentation: - swagger: - v2: - path: /api-docs +springdoc: + writer-with-order-by-keys: true + api-docs: + path: /api-docs #### Custom ReportPortal Properties ######