From fd022ee0d472ee4473b1196f63f06793d8be6ddc Mon Sep 17 00:00:00 2001 From: bnasslah Date: Thu, 20 Jan 2022 23:14:54 +0100 Subject: [PATCH] Reverse proxy context path aware support for manually provided files. Fixes #1453. --- .../core/SwaggerUiConfigParameters.java | 2 +- .../core/SwaggerUiConfigProperties.java | 13 +++++ .../springdoc/ui/AbstractSwaggerWelcome.java | 19 ++++++- .../webmvc/ui/SwaggerWelcomeActuator.java | 5 ++ .../webmvc/ui/SwaggerWelcomeWebMvc.java | 7 ++- .../ui/app29/SpringDocApp29Test.java | 50 ++++++++++++++++++ .../ui/app30/SpringDocApp30Test.java | 52 +++++++++++++++++++ .../webflux/ui/SwaggerWelcomeActuator.java | 5 ++ .../webflux/ui/SwaggerWelcomeWebFlux.java | 7 ++- 9 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app29/SpringDocApp29Test.java create mode 100644 springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app30/SpringDocApp30Test.java diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigParameters.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigParameters.java index d21487628..3fb7622a4 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigParameters.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigParameters.java @@ -129,7 +129,7 @@ public SwaggerUiConfigParameters(SwaggerUiConfigProperties swaggerUiConfig) { this.showExtensions = swaggerUiConfig.getShowExtensions(); this.supportedSubmitMethods = swaggerUiConfig.getSupportedSubmitMethods(); this.url = swaggerUiConfig.getUrl(); - this.urls = swaggerUiConfig.getUrls() == null ? new HashSet<>() : swaggerUiConfig.getUrls(); + this.urls = swaggerUiConfig.getUrls() == null ? new HashSet<>() : swaggerUiConfig.cloneUrls(); this.urlsPrimaryName = swaggerUiConfig.getUrlsPrimaryName(); this.groupsOrder = swaggerUiConfig.getGroupsOrder(); this.tryItOutEnabled = swaggerUiConfig.getTryItOutEnabled(); diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigProperties.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigProperties.java index 3a19f6ade..ce7bd3bb2 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigProperties.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SwaggerUiConfigProperties.java @@ -20,6 +20,9 @@ package org.springdoc.core; +import java.util.Set; +import java.util.stream.Collectors; + import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -372,4 +375,14 @@ public SyntaxHighlight getSyntaxHighlight() { public void setSyntaxHighlight(SyntaxHighlight syntaxHighlight) { this.syntaxHighlight = syntaxHighlight; } + + /** + * Clone urls set. + * + * @return the set + */ + public Set cloneUrls(){ + return this.urls.stream().map(swaggerUrl -> new SwaggerUrl(swaggerUrl.getName(), swaggerUrl.getUrl())).collect(Collectors.toSet()); + } + } \ No newline at end of file diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/ui/AbstractSwaggerWelcome.java b/springdoc-openapi-common/src/main/java/org/springdoc/ui/AbstractSwaggerWelcome.java index 6f15565f3..fc109fbbd 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/ui/AbstractSwaggerWelcome.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/ui/AbstractSwaggerWelcome.java @@ -120,15 +120,32 @@ protected void buildConfigUrl(UriComponentsBuilder uriComponentsBuilder) { String swaggerUiUrl = swaggerUiConfig.getUrl(); if (StringUtils.isEmpty(swaggerUiUrl)) swaggerUiConfigParameters.setUrl(apiDocsUrl); - else + else if (swaggerUiConfigParameters.isValidUrl(swaggerUiUrl)) swaggerUiConfigParameters.setUrl(swaggerUiUrl); + else + swaggerUiConfigParameters.setUrl(buildUrlWithContextPath(swaggerUiUrl)); } else swaggerUiConfigParameters.addUrl(apiDocsUrl); + if (!CollectionUtils.isEmpty(swaggerUiConfig.getUrls())) { + swaggerUiConfigParameters.setUrls(swaggerUiConfig.cloneUrls()); + swaggerUiConfigParameters.getUrls().forEach(swaggerUrl -> { + if (!swaggerUiConfigParameters.isValidUrl(swaggerUrl.getUrl())) + swaggerUrl.setUrl(buildUrlWithContextPath(swaggerUrl.getUrl())); + }); + } } calculateOauth2RedirectUrl(uriComponentsBuilder); } + /** + * Build swagger ui url string. + * + * @param swaggerUiUrl the swagger ui url + * @return the string + */ + protected abstract String buildUrlWithContextPath(String swaggerUiUrl); + /** * Gets uri components builder. * diff --git a/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeActuator.java b/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeActuator.java index 5ac863b61..93d30ea43 100644 --- a/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeActuator.java +++ b/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeActuator.java @@ -85,6 +85,11 @@ protected String buildApiDocUrl() { return buildUrl(contextPath + webEndpointProperties.getBasePath(), DEFAULT_API_DOCS_ACTUATOR_URL); } + @Override + protected String buildUrlWithContextPath(String swaggerUiUrl) { + return buildUrl(contextPath + webEndpointProperties.getBasePath(), swaggerUiUrl); + } + @Override protected String buildSwaggerConfigUrl() { return contextPath + webEndpointProperties.getBasePath() diff --git a/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java b/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java index 162e553a2..2409326fb 100644 --- a/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java +++ b/springdoc-openapi-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java @@ -122,9 +122,14 @@ protected String buildUrl(String contextPath, final String docsUrl) { */ @Override protected String buildApiDocUrl() { + return buildUrlWithContextPath(springDocConfigProperties.getApiDocs().getPath()); + } + + @Override + protected String buildUrlWithContextPath(String swaggerUiUrl) { if (this.pathPrefix == null) this.pathPrefix = springWebProvider.findPathPrefix(springDocConfigProperties); - return buildUrl(contextPath + pathPrefix, springDocConfigProperties.getApiDocs().getPath()); + return buildUrl(contextPath + pathPrefix, swaggerUiUrl); } /** diff --git a/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app29/SpringDocApp29Test.java b/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app29/SpringDocApp29Test.java new file mode 100644 index 000000000..a8eaa1823 --- /dev/null +++ b/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app29/SpringDocApp29Test.java @@ -0,0 +1,50 @@ +/* + * + * * Copyright 2019-2020 the original author or authors. + * * + * * 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 + * * + * * https://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 test.org.springdoc.ui.app29; + +import org.junit.jupiter.api.Test; +import test.org.springdoc.ui.AbstractSpringDocTest; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.context.TestPropertySource; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@TestPropertySource(properties ={ + "springdoc.swagger-ui.url=/api-docs/xxx/v1/openapi.yml", + "server.servlet.context-path=/context-path" +} ) +public class SpringDocApp29Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp {} + + @Test + public void test_url_with_context() throws Exception { + mockMvc.perform(get("/context-path/v3/api-docs/swagger-config").contextPath("/context-path")) + .andExpect(status().isOk()) + .andExpect(jsonPath("url", equalTo("/context-path/api-docs/xxx/v1/openapi.yml"))) + .andExpect(jsonPath("configUrl", equalTo("/context-path/v3/api-docs/swagger-config"))) + .andExpect(jsonPath("validatorUrl", equalTo(""))) + .andExpect(jsonPath("oauth2RedirectUrl", equalTo("http://localhost/context-path/swagger-ui/oauth2-redirect.html"))); + } +} \ No newline at end of file diff --git a/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app30/SpringDocApp30Test.java b/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app30/SpringDocApp30Test.java new file mode 100644 index 000000000..d085f6949 --- /dev/null +++ b/springdoc-openapi-ui/src/test/java/test/org/springdoc/ui/app30/SpringDocApp30Test.java @@ -0,0 +1,52 @@ +/* + * + * * Copyright 2019-2020 the original author or authors. + * * + * * 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 + * * + * * https://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 test.org.springdoc.ui.app30; + +import org.junit.jupiter.api.Test; +import test.org.springdoc.ui.AbstractSpringDocTest; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.test.context.TestPropertySource; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@TestPropertySource(properties ={ + "springdoc.swagger-ui..urls[0].url=/api-docs/xxx/v1/openapi.yml", + "springdoc.swagger-ui.urls[0].name=toto", + "server.servlet.context-path=/context-path" +} ) +public class SpringDocApp30Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp {} + + @Test + public void test_urls_with_context() throws Exception { + mockMvc.perform(get("/context-path/v3/api-docs/swagger-config").contextPath("/context-path")) + .andExpect(status().isOk()) + .andExpect(jsonPath("url").doesNotExist()) + .andExpect(jsonPath("urls[0].url", equalTo("/context-path/api-docs/xxx/v1/openapi.yml"))) + .andExpect(jsonPath("urls[0].name", equalTo("toto"))) + .andExpect(jsonPath("validatorUrl", equalTo(""))) + .andExpect(jsonPath("oauth2RedirectUrl", equalTo("http://localhost/context-path/swagger-ui/oauth2-redirect.html"))); + } +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java b/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java index d6aa05bca..a202e7e05 100644 --- a/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java +++ b/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java @@ -133,6 +133,11 @@ protected String buildApiDocUrl() { return buildUrl(contextPath + webEndpointProperties.getBasePath(), DEFAULT_API_DOCS_ACTUATOR_URL); } + @Override + protected String buildUrlWithContextPath(String swaggerUiUrl) { + return buildUrl(contextPath + webEndpointProperties.getBasePath(), swaggerUiUrl); + } + @Override protected String buildSwaggerConfigUrl() { return contextPath + webEndpointProperties.getBasePath() diff --git a/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java b/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java index 4d4a4906a..0eb02f228 100644 --- a/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java +++ b/springdoc-openapi-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java @@ -115,9 +115,14 @@ protected void calculateOauth2RedirectUrl(UriComponentsBuilder uriComponentsBuil */ @Override protected String buildApiDocUrl() { + return buildUrlWithContextPath(springDocConfigProperties.getApiDocs().getPath()); + } + + @Override + protected String buildUrlWithContextPath(String swaggerUiUrl) { if (this.pathPrefix == null) this.pathPrefix = springWebProvider.findPathPrefix(springDocConfigProperties); - return buildUrl(this.contextPath + this.pathPrefix, springDocConfigProperties.getApiDocs().getPath()); + return buildUrl(this.contextPath + this.pathPrefix,swaggerUiUrl ); } /**