Swagger Parser

repository·master·Indexed 21 days ago

https://github.com/swagger-api/swagger-parser

A tool for parsing, validating, and resolving OpenAPI and Swagger specifications. It supports OpenAPI 3.1 (since v2.1.0) and automatically converts OpenAPI 2.0 documents to 3.0. Key features include the OpenAPIParser for reading definitions from URLs, files, or strings, and the PermittedUrlsChecker for protecting against SSRF and DNS rebinding attacks. The library provides customization via ParseOptions for resolving references and flattening files, and supports extensions through the Java Service Provider Interface (SPI).

Tokens
3K
Snippets
8
Records
12
Agent score
25%

What's inside swagger-parser

  1. Overview of Swagger Parser

    master

    Swagger Parser is a library used to parse and validate OpenAPI and Swagger specifications.

    Version Compatibility Notes:

    • OpenAPI 3.1: Supported since version 2.1.0.
    • Legacy Support: If you require swagger-parser 1.X or specifically OpenAPI 2.0 support, you should use the v1 branch of the repository.
  2. Implement a SwaggerParserExtension

    master

    The parser uses the Java Service Provider Interface (SPI) to allow for extensions. To create a custom extension:

    1. Implement the io.swagger.v3.parser.core.extensions.SwaggerParserExtension interface.
    2. Create a file named src/main/resources/META-INF/services/io.swagger.v3.parser.core.extensions.SwaggerParserExtension containing the full class name of your implementation.
    3. Include your library in your project; the parser will automatically detect and trigger your extension.
  3. How PermittedUrlsChecker works

    master

    The PermittedUrlsChecker is designed to protect against Server-Side Request Forgery (SSRF) and DNS rebinding attacks by verifying that a URL's hostname does not resolve to a private or restricted IPv4/IPv6 address range.

    When you call verify(String url), the library performs these steps:

    1. Extracts the hostname from the provided URL.
    2. Resolves the hostname to an IP address.
    3. Validates the IP against restricted ranges (throwing an exception if it matches a restricted range and is not allowlisted).
    4. Returns a ResolvedUrl object containing:
      • url: The original URL, but with the hostname replaced by the resolved IP address.
      • hostHeader: The original hostname, intended to be used as a Host header in subsequent requests.

    Customization:

    • Allowlist: Entries in the allowlist permit a URL to pass even if its IP resolves to a private/restricted range.
    • Denylist: Entries in the denylist will cause a HostDeniedException even if the URL resolves to a public IP address.
    // Conceptual usage of the verification flow
    ResolvedUrl resolvedUrl = checker.verify("https://github.com/swagger-api/swagger-parser");
    // resolvedUrl.getUrl() will contain the IP-based URL
    // resolvedUrl.getHostHeader() will contain "github.com"
  4. Add Swagger Parser to your Maven project

    master

    Include the swagger-parser dependency in your pom.xml.

    Prerequisites:

    • Java 11
    • Apache Maven 3.x

    To build the project from source, use:

    mvn package
    <dependency>
      <groupId>io.swagger.parser.v3</groupId>
      <artifactId>swagger-parser</artifactId>
      <version>2.1.46</version>
    </dependency>
  5. Install swagger-parser-safe-url-resolver via Maven

    master

    To use the safe URL resolver in your Java project, add the following dependency to your pom.xml file. Ensure the version matches the version of swagger-parser you are currently using.

    <dependency>
        <groupId>io.swagger.parser.v3</groupId>
        <artifactId>swagger-parser-safe-url-resolver</artifactId>
        <!-- version of swagger-parser being used -->
        <version>2.1.14</version> 
    </dependency>
  6. Configure ParseOptions for customization

    master

    The ParseOptions class allows you to customize how the parser handles references and schema structures.

    Key options include:

    • setResolve(boolean): Resolves remote or relative references and adds them to the local components section.
    • setResolveFully(boolean): (Requires resolve to be true) Removes all local references by replacing them with the actual content of the referenced element.
    • setFlatten(boolean): Moves inline schemas into the components/schemas section and replaces them with references.
    • setResolveCombinators(boolean): (Requires resolveFully to be true) Controls how allOf/anyOf/oneOf are processed. If true (default), it merges properties into a single schema. If false, it maintains the composed structure.
    • setExplicitObjectSchema(boolean): (Requires resolveFully to be true) If true (default), properties without a defined type are assigned the type object. If false, they remain undefined.
  7. Disable SSL certificate validation

    master

    To handle self-signed SSL certificates or environments with untrusted CAs, you can disable the SSL Trust Manager by setting the TRUST_ALL environment variable to true.

    Warning: This is insecure and should only be used in controlled environments (e.g., behind a firewall).

    export TRUST_ALL=true
  8. Use PermittedUrlsChecker to verify URLs

    master

    Use the PermittedUrlsChecker to validate URLs against private IP ranges and custom allow/deny lists. This is useful when handling user-submitted URLs that your service needs to fetch.

    Key Classes:

    • io.swagger.v3.parser.urlresolver.PermittedUrlsChecker: The main engine for verification.
    • io.swagger.v3.parser.urlresolver.models.ResolvedUrl: The result object containing the IP-replaced URL and the original host header.
    • io.swagger.v3.parser.urlresolver.exceptions.HostDeniedException: The exception thrown when a URL is deemed unsafe.
    import io.swagger.v3.parser.urlresolver.PermittedUrlsChecker;
    import io.swagger.v3.parser.urlresolver.exceptions.HostDeniedException;
    import io.swagger.v3.parser.urlresolver.models.ResolvedUrl;
    
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) {
            List<String> allowlist = List.of("mysite.local");
            List<String> denylist = List.of("*.example.com:443");
            var checker = new PermittedUrlsChecker(allowlist, denylist);
    
            try {
                // 1. Fails: localhost resolves to local IP and is not in allowlist
                // checker.verify("http://localhost/example");
    
                // 2. Succeeds: github.com resolves to a public IP
                // checker.verify("https://github.com/swagger-api/swagger-parser");
    
                // 3. Fails: *.example.com is explicitly deny listed
                // checker.verify("https://subdomain.example.com/somepage");
    
                // 4. Succeeds: mysite.local is explicitly allowlisted
                ResolvedUrl resolvedUrl = checker.verify("http://mysite.local/example");
                System.out.println(resolvedUrl.getUrl()); // "http://127.0.0.1/example"
                System.out.println(resolvedUrl.getHostHeader()); // "mysite.local"
            } catch (HostDeniedException e) {
                e.printStackTrace();
            }
        }
    }
  9. Authenticate requests with headers

    master

    If your OpenAPI definition is protected, use AuthorizationValue to pass authentication headers or query parameters. You can pass a list of these values to readWithInfo in OpenAPIV3Parser.

    import io.swagger.v3.parser.OpenAPIV3Parser;
    import io.swagger.v3.parser.core.models.AuthorizationValue;
    import io.swagger.v3.oas.models.OpenAPI;
    import java.util.Arrays;
    
    // Build an authorization value for a header
    AuthorizationValue mySpecialHeader = new AuthorizationValue()
      .keyName("x-special-access")
      .value("i-am-special")
      .type("header");
    
    // Or use the shorthand constructor: AuthorizationValue(name, value, type)
    AuthorizationValue apiKey = new AuthorizationValue("api_key", "special-key", "header");
    
    OpenAPI openAPI = new OpenAPIV3Parser().readWithInfo(
      "https://petstore3.swagger.io/api/v3/openapi.json",
      Arrays.asList(mySpecialHeader, apiKey)
    );
  10. Parse OpenAPI definitions with OpenAPIParser

    master

    Use OpenAPIParser to read OpenAPI specifications from a URL, a file path, or a string. The parser returns a SwaggerParseResult which contains the parsed OpenAPI POJO and any validation messages (errors or warnings).

    Note: If you provide a Swagger/OpenAPI 2.0 document, it will be automatically converted to OpenAPI 3.0.

    import io.swagger.parser.OpenAPIParser;
    import io.swagger.v3.parser.core.models.SwaggerParseResult;
    import io.swagger.v3.oas.models.OpenAPI;
    
    // Parse from a URL or file location
    SwaggerParseResult result = new OpenAPIParser().readLocation("https://petstore3.swagger.io/api/v3/openapi.json", null, null);
    
    // Parse from string contents
    // SwaggerParseResult result = new OpenAPIParser().readContents("contents", null, null);
    
    OpenAPI openAPI = result.getOpenAPI();
    
    // Handle validation errors and warnings
    if (result.getMessages() != null) {
      result.getMessages().forEach(System.err::println);
    }
    
    if (openAPI != null) {
      // Use the parsed model
    }
  11. Parse OpenAPI 3.0 documents with OpenAPIV3Parser

    master

    If you are working exclusively with OpenAPI 3.0 documents, you can use OpenAPIV3Parser. This class provides a convenience method read() that returns the OpenAPI object directly, bypassing the SwaggerParseResult wrapper.

    import io.swagger.v3.parser.OpenAPIV3Parser;
    import io.swagger.v3.oas.models.OpenAPI;
    
    // Directly get the OpenAPI object
    OpenAPI openAPI = new OpenAPIV3Parser().read("https://petstore3.swagger.io/api/v3/openapi.json");