Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Apache Paimon DLFOpenApiSigner

From Leeroopedia


Knowledge Sources
Domains Authentication, Alibaba Cloud, OpenAPI, Request Signing
Last Updated 2026-02-08 00:00 GMT

Overview

DLFOpenApiSigner implements Alibaba Cloud OpenAPI signature authentication for DlfNext (2026-01-18) service endpoints using HMAC-SHA1.

Description

DLFOpenApiSigner is a specialized implementation of DLFRequestSigner designed for the newer Alibaba Cloud OpenAPI protocol, specifically targeting the DlfNext service (API version 2026-01-18). Unlike the default signer which uses HMAC-SHA256, this signer implements the ROA (Resource Oriented Architecture) signing mechanism using HMAC-SHA1, which is the standard for Aliyun OpenAPI services.

The signing process follows Alibaba Cloud's OpenAPI ROA signature specification, which differs significantly from the traditional DLF VPC endpoint protocol. The signer constructs headers in a specific format required by OpenAPI, including GMT-formatted Date header, Accept and Content-Type headers for JSON, and various x-acs-* headers for signature metadata (signature method, nonce, signature version, and API version).

The signature calculation involves building a canonicalized representation of the request. This includes canonicalizing x-acs-* headers by sorting them alphabetically and formatting them as key:value pairs; canonicalizing the resource path and query parameters by decoding URLs and sorting parameters; and constructing a StringToSign from the HTTP method, Accept, Content-MD5, Content-Type, Date, canonicalized headers, and canonicalized resource.

A critical aspect of this implementation is its careful handling of URL encoding. The canonicalized resource must use decoded values to ensure signature consistency, as different URL encoding schemes could produce different signatures for logically equivalent requests. The signer properly decodes both the resource path and query parameter values before including them in the signature calculation.

Usage

Use DLFOpenApiSigner when connecting to Alibaba Cloud DlfNext OpenAPI endpoints (identifiable by "dlfnext" in the hostname). This signer is automatically selected when the signing algorithm is set to "openapi" or when auto-detection determines the endpoint is a DlfNext service endpoint.

Code Reference

Source Location

Signature

public class DLFOpenApiSigner implements DLFRequestSigner {
    public static final String IDENTIFIER = "openapi";

    private static final String HMAC_SHA1 = "HmacSHA1";
    private static final String DATE_HEADER = "Date";
    private static final String ACCEPT_HEADER = "Accept";
    private static final String CONTENT_MD5_HEADER = "Content-MD5";
    private static final String CONTENT_TYPE_HEADER = "Content-Type";
    private static final String HOST_HEADER = "Host";
    private static final String X_ACS_SIGNATURE_METHOD = "x-acs-signature-method";
    private static final String X_ACS_SIGNATURE_NONCE = "x-acs-signature-nonce";
    private static final String X_ACS_SIGNATURE_VERSION = "x-acs-signature-version";
    private static final String X_ACS_VERSION = "x-acs-version";
    private static final String X_ACS_SECURITY_TOKEN = "x-acs-security-token";

    private static final String SIGNATURE_METHOD_VALUE = "HMAC-SHA1";
    private static final String SIGNATURE_VERSION_VALUE = "1.0";
    private static final String API_VERSION = "2026-01-18";

    @Override
    public Map<String, String> signHeaders(
            @Nullable String body, Instant now, @Nullable String securityToken, String host);

    @Override
    public String authorization(
            RESTAuthParameter restAuthParameter,
            DLFToken token,
            String host,
            Map<String, String> signHeaders) throws Exception;

    @Override
    public String identifier();
}

Import

import org.apache.paimon.rest.auth.DLFOpenApiSigner;

I/O Contract

Inputs

Name Type Required Description
body String No Request body for MD5 calculation
now Instant Yes Current timestamp for Date header (GMT format)
securityToken String No Security token for temporary credentials
host String Yes Host header value
restAuthParameter RESTAuthParameter Yes Request parameters (path, method, query params)
token DLFToken Yes DLF token containing access key ID and secret
signHeaders Map<String, String> Yes Headers generated by signHeaders() method

Outputs

Name Type Description
signHeaders() Map<String, String> Returns headers including Date, Accept, Host, x-acs-* headers
authorization() String Returns Authorization header value: "acs <accessKeyId>:<signature>"
identifier() String Returns "openapi" as the signer identifier

Usage Examples

import org.apache.paimon.rest.auth.DLFOpenApiSigner;
import org.apache.paimon.rest.auth.DLFToken;
import org.apache.paimon.rest.auth.RESTAuthParameter;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

// Example 1: Create OpenAPI signer
DLFOpenApiSigner signer = new DLFOpenApiSigner();

// Example 2: Generate sign headers for GET request
Instant now = Instant.now();
Map<String, String> signHeaders = signer.signHeaders(
    null,  // no body for GET
    now,
    null,  // no security token
    "dlfnext.cn-hangzhou.aliyuncs.com"
);

// Sign headers include:
// Date: Wed, 08 Feb 2026 12:00:00 GMT
// Accept: application/json
// Host: dlfnext.cn-hangzhou.aliyuncs.com
// x-acs-signature-method: HMAC-SHA1
// x-acs-signature-nonce: <uuid>
// x-acs-signature-version: 1.0
// x-acs-version: 2026-01-18

// Example 3: Generate sign headers for POST request with body
String requestBody = "{\"name\":\"my_table\",\"schema\":{...}}";
Map<String, String> postHeaders = signer.signHeaders(
    requestBody,
    now,
    null,
    "dlfnext.cn-hangzhou.aliyuncs.com"
);

// Additional headers for POST:
// Content-MD5: <base64-encoded-md5>
// Content-Type: application/json

// Example 4: Generate sign headers with security token (STS)
Map<String, String> stsHeaders = signer.signHeaders(
    null,
    now,
    "STS_security_token_value",
    "dlfnext.cn-hangzhou.aliyuncs.com"
);

// Additional header:
// x-acs-security-token: STS_security_token_value

// Example 5: Generate authorization header
DLFToken token = new DLFToken("LTAI***", "secret***", null, null);

RESTAuthParameter authParam = new RESTAuthParameter(
    "/api/v1/tables",
    new HashMap<>(),
    "GET",
    ""
);

String authorization = signer.authorization(
    authParam,
    token,
    "dlfnext.cn-hangzhou.aliyuncs.com",
    signHeaders
);

// Authorization format:
// acs LTAI***:<base64-hmac-sha1-signature>

// Example 6: Complete signing workflow for OpenAPI
public Map<String, String> signOpenApiRequest(
        String method,
        String path,
        Map<String, String> queryParams,
        String body,
        DLFToken token,
        String host) throws Exception {

    DLFOpenApiSigner signer = new DLFOpenApiSigner();
    Instant now = Instant.now();

    // Step 1: Generate sign headers
    Map<String, String> signHeaders = signer.signHeaders(
        body,
        now,
        token.getSecurityToken(),
        host
    );

    // Step 2: Create auth parameter
    RESTAuthParameter authParam = new RESTAuthParameter(
        path,
        queryParams,
        method,
        body
    );

    // Step 3: Generate authorization
    String authorization = signer.authorization(
        authParam,
        token,
        host,
        signHeaders
    );

    // Step 4: Combine all headers
    Map<String, String> allHeaders = new HashMap<>(signHeaders);
    allHeaders.put("Authorization", authorization);

    return allHeaders;
}

// Example 7: POST request with query parameters
Map<String, String> queryParams = new HashMap<>();
queryParams.put("namespace", "default");
queryParams.put("createMode", "overwrite");

String postBody = "{\"schema\":{...}}";

Map<String, String> headers = signOpenApiRequest(
    "POST",
    "/api/v1/tables/my_table",
    queryParams,
    postBody,
    token,
    "dlfnext.cn-hangzhou.aliyuncs.com"
);

// Example 8: Request with special characters (automatically decoded for signature)
Map<String, String> specialHeaders = signOpenApiRequest(
    "GET",
    "/api/v1/tables/my_table%24partition",  // URL-encoded path
    new HashMap<>(),
    "",
    token,
    "dlfnext.cn-hangzhou.aliyuncs.com"
);
// Path is decoded to "/api/v1/tables/my_table$partition" for signature

// Example 9: Compare with default signer
import org.apache.paimon.rest.auth.DLFDefaultSigner;

DLFDefaultSigner defaultSigner = new DLFDefaultSigner("cn-hangzhou");
DLFOpenApiSigner openApiSigner = new DLFOpenApiSigner();

System.out.println("Default signer: " + defaultSigner.identifier());  // "default"
System.out.println("OpenAPI signer: " + openApiSigner.identifier());  // "openapi"

// Default uses: DLF4-HMAC-SHA256 with region-specific credentials
// OpenAPI uses: HMAC-SHA1 with acs prefix

// Example 10: Handling query parameters with special characters
Map<String, String> complexParams = new HashMap<>();
complexParams.put("filter", "type=managed");
complexParams.put("name", "table with spaces");

// Query parameters are decoded for signature calculation:
// filter=type=managed&name=table with spaces

Map<String, String> complexHeaders = signOpenApiRequest(
    "GET",
    "/api/v1/tables",
    complexParams,
    "",
    token,
    "dlfnext.cn-hangzhou.aliyuncs.com"
);

// Example 11: Date header format
SimpleDateFormat dateFormat = new SimpleDateFormat(
    "EEE, dd MMM yyyy HH:mm:ss 'GMT'",
    Locale.ENGLISH
);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

String dateHeader = dateFormat.format(Date.from(now));
// Example: "Wed, 08 Feb 2026 12:00:00 GMT"

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment