Skip to content

Commit

Permalink
fix: do not leak 'exampleSetFlag' in api doc (v3.x.x) (#3933)
Browse files Browse the repository at this point in the history
* fix - do not leak 'exampleSetFlag' in api doc

Signed-off-by: nx673747 <[email protected]>

* fix failing tests

Signed-off-by: nx673747 <[email protected]>

---------

Signed-off-by: nx673747 <[email protected]>
Co-authored-by: nx673747 <[email protected]>
  • Loading branch information
nxhafa and nx673747 authored Dec 17, 2024
1 parent 3fb0d59 commit ee31cd9
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.swagger.v3.core.jackson.mixin.MediaTypeMixin;
import io.swagger.v3.core.jackson.mixin.SchemaMixin;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
Expand Down Expand Up @@ -47,11 +51,8 @@ public class ApiDocV3Service extends AbstractApiDocService<OpenAPI, PathItem> {
@Value("${gateway.scheme.external:https}")
private String scheme;

private final ObjectMapper mapper;

public ApiDocV3Service(GatewayClient gatewayClient) {
super(gatewayClient);
mapper = initializeObjectMapper();
}

public String transformApiDoc(String serviceId, ApiDocInfo apiDocInfo) {
Expand Down Expand Up @@ -79,7 +80,7 @@ public String transformApiDoc(String serviceId, ApiDocInfo apiDocInfo) {
updateExternalDoc(openAPI, apiDocInfo);

try {
return mapper.writeValueAsString(openAPI);
return objectMapper().writeValueAsString(openAPI);
} catch (JsonProcessingException e) {
log.debug("Could not convert OpenAPI to JSON", e);
throw new ApiDocTransformationException("Could not convert Swagger to JSON");
Expand Down Expand Up @@ -195,17 +196,13 @@ private boolean isHidden(List<Tag> tags) {
return tags != null && tags.stream().anyMatch(tag -> tag.getName().equals(HIDDEN_TAG));
}

private ObjectMapper initializeObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(SecurityScheme.class, new SecuritySchemeSerializer());

objectMapper.registerModule(simpleModule);
objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);

objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
private ObjectMapper objectMapper() {
return new ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(new SimpleModule().addSerializer(SecurityScheme.class, new SecuritySchemeSerializer()))
.registerModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
.addMixIn(Schema.class, SchemaMixin.class)
.addMixIn(MediaType.class, MediaTypeMixin.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.zowe.apiml.product.gateway.GatewayClient;

import jakarta.validation.UnexpectedTypeException;

import java.io.IOException;
import java.util.function.Function;

Expand All @@ -42,8 +43,8 @@ public class ApiTransformationConfig {
@Bean
@Scope(value = "prototype")
public AbstractApiDocService<?, ?> abstractApiDocService(String content) {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectMapper mapper = new ObjectMapper(new YAMLFactory())
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
try {
ObjectNode objectNode = mapper.readValue(content, ObjectNode.class);
JsonNode openApiNode = objectNode.get("openapi");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.zowe.apiml.product.routing.RoutedServices;

import jakarta.validation.UnexpectedTypeException;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
Expand Down Expand Up @@ -88,7 +89,7 @@ void givenOpenApiValidJson() {
RoutedServices routedServices = new RoutedServices();
routedServices.addRoutedService(routedService);
routedServices.addRoutedService(routedService2);
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc",null, "https://www.zowe.org");
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc", null, "https://www.zowe.org");
ApiDocInfo apiDocInfo = new ApiDocInfo(apiInfo, apiDocContent, routedServices);

String actualContent = apiDocV3Service.transformApiDoc(SERVICE_ID, apiDocInfo);
Expand Down Expand Up @@ -175,7 +176,7 @@ class ThenThrowException {
@Test
void givenEmptyJson() {
String invalidJson = "";
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc",null, "https://www.zowe.org");
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc", null, "https://www.zowe.org");
ApiDocInfo apiDocInfo = new ApiDocInfo(apiInfo, invalidJson, null);

Exception exception = assertThrows(UnexpectedTypeException.class, () -> apiDocV3Service.transformApiDoc(SERVICE_ID, apiDocInfo));
Expand All @@ -187,7 +188,7 @@ void givenInvalidJson() {
String invalidJson = "nonsense";
String error = "The OpenAPI for service 'serviceId' was retrieved but was not a valid JSON document. '[Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('nonsense')\n" +
" at [Source: UNKNOWN; byte offset: #UNKNOWN]]'";
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc",null, "https://www.zowe.org");
ApiInfo apiInfo = new ApiInfo(API_ID, "api/v1", API_VERSION, "https://localhost:10014/apicatalog/api-doc", null, "https://www.zowe.org");
ApiDocInfo apiDocInfo = new ApiDocInfo(apiInfo, invalidJson, null);

Exception exception = assertThrows(UnexpectedTypeException.class, () -> apiDocV3Service.transformApiDoc(SERVICE_ID, apiDocInfo));
Expand Down Expand Up @@ -239,14 +240,28 @@ protected void updateExternalDoc(OpenAPI openAPI, ApiDocInfo apiDocInfo) {
}
};
String transformed = apiDocV3Service.transformApiDoc("serviceId", new ApiDocInfo(
mock(ApiInfo.class),
IOUtils.toString(new ClassPathResource("swagger/openapi3.json").getInputStream(), StandardCharsets.UTF_8),
mock(RoutedServices.class)
mock(ApiInfo.class),
IOUtils.toString(new ClassPathResource("swagger/openapi3.json").getInputStream(), StandardCharsets.UTF_8),
mock(RoutedServices.class)
));
assertNotNull(transformed);
verifyOpenApi3(openApiHolder.get());
}

@Test
void givenValidApiDoc_thenDoNotLeakExampleSetFlag() throws IOException {
ApiInfo apiInfo = new ApiInfo("zowe.apiml.apicatalog", "api/v1", API_VERSION, "https://localhost:10014/apicatalog/v3/api-docs", null, "https://www.zowe.org");
String content = IOUtils.toString(new ClassPathResource("swagger/openapi3.json").getInputStream(), StandardCharsets.UTF_8);

RoutedServices routedServices = new RoutedServices();
routedServices.addRoutedService(new RoutedService("api-v1", "api/v1", "/apicatalog"));

ApiDocInfo info = new ApiDocInfo(apiInfo, content, routedServices);
assertThat(content, containsString("\"exampleSetFlag\":"));

String actualContent = apiDocV3Service.transformApiDoc(SERVICE_ID, info);
assertThat(actualContent, not(containsString("\"exampleSetFlag\":")));
}
}

private String convertOpenApiToJson(OpenAPI openApi) {
Expand Down

0 comments on commit ee31cd9

Please sign in to comment.