From de8a9c539b1ee388ff06450024f1815df9228fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9F=A9=E8=B4=A4=E6=B6=9B?= <601803023@qq.com> Date: Sun, 21 Sep 2025 14:34:07 +0800 Subject: [PATCH] doc: optimize the documentation for hmac-auth-apisix (#2912) --- .../extensions/hmac-auth-apisix/README.md | 174 ++++++++++- .../extensions/hmac-auth-apisix/README_EN.md | 278 ++++++++++++++---- 2 files changed, 372 insertions(+), 80 deletions(-) diff --git a/plugins/wasm-go/extensions/hmac-auth-apisix/README.md b/plugins/wasm-go/extensions/hmac-auth-apisix/README.md index 6ed560847..c02667362 100644 --- a/plugins/wasm-go/extensions/hmac-auth-apisix/README.md +++ b/plugins/wasm-go/extensions/hmac-auth-apisix/README.md @@ -81,17 +81,159 @@ allow: ``` **配置说明**: + - 路由名称(如 route-a、route-b)对应网关路由创建时定义的名称,匹配时仅允许consumer1访问 - 域名匹配(如 `*.example.com`、`test.com`)用于过滤请求域名,匹配时仅允许consumer2访问 - 未在allow列表中的调用者将被拒绝访问 +**生成签名,可以使用以下 Go 代码片段或其他技术栈**: + +```go +package main + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/base64" + "fmt" + "hash" + "strings" + "time" +) + +// SignedHeader 定义签名头的结构 +type SignedHeader struct { + Name string + Value string +} + +func main() { + // 配置参数 + keyID := "consumer1-key" // key id + secretKey := "2bda943c-ba2b-11ec-ba07-00163e1250b5" // secret key + requestMethod := "POST" // HTTP method + requestPath := "/foo" // Route URI + algorithm := "hmac-sha256" // algorithm + validateRequestBody := false // 是否验证请求体,设置为true时会添加Digest头部 + + // 如果配置了 signed_headers,则需要按照顺序添加 + signedHeaders := []SignedHeader{ + //{Name: "x-custom-header-a", Value: "test1"}, + //{Name: "x-custom-header-b", Value: "test2"}, + } + + body := []byte("{}") // request body + + // 获取当前 GMT 时间 + gmtTime := time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT") + + // 动态构造签名字符串(有序) + signingStringBuilder := strings.Builder{} + signingStringBuilder.WriteString(fmt.Sprintf("%s\n%s %s\ndate: %s\n", + keyID, + requestMethod, + requestPath, + gmtTime)) + + // 按照signedHeaders中的顺序添加header + for _, header := range signedHeaders { + signingStringBuilder.WriteString(fmt.Sprintf("%s: %s\n", header.Name, header.Value)) + } + + signingString := signingStringBuilder.String() + + // 创建签名 + signature, err := generateHmacSignature(secretKey, algorithm, signingString) + if err != nil { + fmt.Printf("Error generating signature: %v\n", err) + return + } + + // 动态构建headers字段内容 + headersField := "@request-target date" + for _, header := range signedHeaders { + headersField += " " + header.Name + } + + // 构造请求头部 + headers := map[string]string{ + "Date": gmtTime, + "Authorization": fmt.Sprintf(`Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"`, + keyID, + algorithm, + headersField, + signature, + ), + } + + // 如果需要验证请求体,则添加Digest头部 + if validateRequestBody { + headers["Digest"] = calculateBodyDigest(body) + } + + // 添加签名的请求头 + for _, header := range signedHeaders { + formattedHeaderName := formatHeaderName(header.Name) + headers[formattedHeaderName] = header.Value + } + + // 打印签名字符串 + fmt.Printf("signingString: %s\n", signingString) + // 打印请求头 + fmt.Println("Headers:") + for key, value := range headers { + fmt.Printf("%s: %s\n", key, value) + } +} + +// generateHmacSignature 生成HMAC签名 +func generateHmacSignature(secretKey, algorithm, message string) (string, error) { + var mac hash.Hash + + switch algorithm { + case "hmac-sha1": + mac = hmac.New(sha1.New, []byte(secretKey)) + case "hmac-sha256": + mac = hmac.New(sha256.New, []byte(secretKey)) + case "hmac-sha512": + mac = hmac.New(sha512.New, []byte(secretKey)) + default: + return "", fmt.Errorf("unsupported algorithm: %s", algorithm) + } + + mac.Write([]byte(message)) + signature := mac.Sum(nil) + return base64.StdEncoding.EncodeToString(signature), nil +} + +// calculateBodyDigest 计算body的摘要 +func calculateBodyDigest(body []byte) string { + hash := sha256.Sum256(body) + encodedDigest := base64.StdEncoding.EncodeToString(hash[:]) + return "SHA-256=" + encodedDigest +} + +// formatHeaderName 将header name转换为标准HTTP头格式 +func formatHeaderName(headerName string) string { + parts := strings.Split(headerName, "-") + for i, part := range parts { + if len(part) > 0 { + parts[i] = strings.ToUpper(part[:1]) + strings.ToLower(part[1:]) + } + } + return strings.Join(parts, "-") +} +``` + **请求与响应示例**: 1. **验证通过场景** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="G2+60rCCHQCQDZOailnKHLCEy++P1Pa5OEP1bG4QlRo="' \ --H 'Date:Sat, 30 Aug 2025 00:52:39 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ -H 'Content-Type: application/json' \ -d '{}' ``` @@ -101,8 +243,8 @@ curl -X POST 'http://localhost:8082/foo' \ 2. **请求方法修改导致验签失败** ```shell curl -X PUT 'http://localhost:8082/foo' \ # 此处将POST改为PUT --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="G2+60rCCHQCQDZOailnKHLCEy++P1Pa5OEP1bG4QlRo="' \ --H 'Date:Sat, 30 Aug 2025 00:52:39 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ -H 'Content-Type: application/json' \ -d '{}' ``` @@ -112,8 +254,8 @@ curl -X PUT 'http://localhost:8082/foo' \ # 此处将POST改为PUT 3. **不在允许列表中的调用者** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer2-key",algorithm="hmac-sha256",headers="@request-target date",signature="5sqSbDX9b91dQsfQra2hpluM7O6/yhS7oLcKPQylyCo="' \ --H 'Date:Sat, 30 Aug 2025 00:54:18 GMT' \ +-H 'Authorization:Signature keyId="consumer2-key",algorithm="hmac-sha256",headers="@request-target date",signature="dltotPwd4iWGGz//kuehPJlHXZemR5WKwCPAJD/KPhE="' \ +-H 'Date:Fri, 12 Sep 2025 23:59:01 GMT' \ -H 'Content-Type: application/json' \ -d '{}' ``` @@ -123,8 +265,8 @@ curl -X POST 'http://localhost:8082/foo' \ 4. **时间戳过期** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization: Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="gvIUwoYNiK57w6xX2g1Ntpk8lfgD7z+jgom434r5qwg="' \ --H 'Date: Sat, 30 Aug 2025 00:40:21 GMT' \ # 过期的时间戳 +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ # 过期的时间戳 -H 'Content-Type: application/json' \ -d '{}' ``` @@ -154,35 +296,37 @@ validate_request_body: true # 启用请求体签名校验 1. **验证通过场景** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="+xCWYCmidq3Sisn08N54NWaau5vSY9qEanWoO9HD4mA="' \ --H 'Date:Sat, 30 Aug 2025 01:04:06 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="KoOlbkDIR/JzlKK47eURewnIpmhpkQU+KIyBUhqVfmo="' \ +-H 'Date:Sat, 13 Sep 2025 00:04:34 GMT' \ -H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ # 请求体摘要 -H 'X-Custom-Header-A:test1' \ -H 'X-Custom-Header-B:test2' \ -H 'Content-Type: application/json' \ -d '{}' ``` + - 响应:返回后端服务正常响应 2. **缺少签名头** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="+xCWYCmidq3Sisn08N54NWaau5vSY9qEanWoO9HD4mA="' \ --H 'Date:Sat, 30 Aug 2025 01:04:06 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-b",signature="KoOlbkDIR/JzlKK47eURewnIpmhpkQU+KIyBUhqVfmo="' \ +-H 'Date:Sat, 13 Sep 2025 00:04:34 GMT' \ -H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ -H 'X-Custom-Header-B:test2' \ # 缺少X-Custom-Header-A -H 'Content-Type: application/json' \ -d '{}' ``` + - 响应:`401 Unauthorized` - 错误信息:`{"message":"client request can't be validated: expected header "X-Custom-Header-A" missing in signing"}` 3. **请求体被篡改** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="dSbv6pdQOcgkN89TmSxiT8F9nypbPUqAR2E7ELL8K2s="' \ --H 'Date:Sat, 30 Aug 2025 01:10:17 GMT' \ --H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ # 与实际body不匹配 +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="NcA+44FFtl2rjNvV28wSn8Rln02i4i2tFXKp3/ahyYA="' \ +-H 'Date:Sat, 13 Sep 2025 00:09:40 GMT' \ +-H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ -H 'X-Custom-Header-A:test1' \ -H 'X-Custom-Header-B:test2' \ -H 'Content-Type: application/json' \ diff --git a/plugins/wasm-go/extensions/hmac-auth-apisix/README_EN.md b/plugins/wasm-go/extensions/hmac-auth-apisix/README_EN.md index 5d5ebbc53..13c16dd28 100644 --- a/plugins/wasm-go/extensions/hmac-auth-apisix/README_EN.md +++ b/plugins/wasm-go/extensions/hmac-auth-apisix/README_EN.md @@ -1,6 +1,7 @@ -# APISIX HMAC Authentication +--- +title: APISIX HMAC Authentication keywords: [higress, hmac auth, apisix] -description: Configuration Reference for APISIX HMAC Authentication Plugin +description: Configuration Reference for the APISIX HMAC Authentication Plugin --- ## Feature Description @@ -50,12 +51,14 @@ The `hmac-auth-apisix` plugin is compatible with Apache APISIX's HMAC authentica ## Configuration Examples -### Global Authentication Configuration and Route-level Authorization -The following configuration enables HMAC Auth authentication and authorization for specific routes or domains of the gateway. **Note: The `access_key` field must be unique.** +### Global Configuration Authentication and Route-Level Authorization + +The following configuration is used to enable Hmac Auth authentication and authorization for specific routes or domains of the gateway. **Note: The `access_key` field must be unique.** #### Example 1: Basic Route and Domain Authorization Configuration -**Instance-level Plugin Configuration**: + +**Instance-Level Plugin Configuration**: ```yaml global_auth: false consumers: @@ -65,78 +68,222 @@ consumers: - name: consumer2 access_key: consumer2-key secret_key: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35 -``` +``` -**Route-level Configuration** (Applicable to `route-a` and `route-b`): +**Route-Level Configuration** (applicable to `route-a` and `route-b`): ```yaml allow: -- consumer1 # Only consumer1 is allowed to access -``` +- consumer1 # Only consumer1 is allowed access +``` -**Domain-level Configuration** (Applicable to `*.example.com` and `test.com`): +**Domain-Level Configuration** (applicable to `*.example.com` and `test.com`): ```yaml allow: -- consumer2 # Only consumer2 is allowed to access -``` +- consumer2 # Only consumer2 is allowed access +``` -**Configuration Description**: -- Route names (e.g., `route-a`, `route-b`) correspond to the names defined when creating gateway routes. Only `consumer1` is allowed to access when the route matches. -- Domain matching (e.g., `*.example.com`, `test.com`) is used to filter request domains. Only `consumer2` is allowed to access when the domain matches. + +#### Configuration Instructions: +- **Route Names** (e.g., `route-a`, `route-b`): Correspond to the names defined when creating gateway routes. Only `consumer1` is allowed access when matched. +- **Domain Matching** (e.g., `*.example.com`, `test.com`): Used to filter request domains. Only `consumer2` is allowed access when matched. - Callers not in the `allow` list will be denied access. -**Request and Response Examples**: +#### To Generate a Signature, Use the Following Go Code Snippet or Other Tech Stacks: -1. **Successful Verification Scenario** +```go +package main + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/base64" + "fmt" + "hash" + "strings" + "time" +) + +// SignedHeader defines the structure of signed headers +type SignedHeader struct { + Name string + Value string +} + +func main() { + // Configuration parameters + keyID := "consumer1-key" // Key ID + secretKey := "2bda943c-ba2b-11ec-ba07-00163e1250b5" // Secret key + requestMethod := "POST" // HTTP method + requestPath := "/foo" // Route URI + algorithm := "hmac-sha256" // Algorithm + validateRequestBody := false // Whether to validate the request body; set to true to add the Digest header + + // If signed_headers is configured, add them in order + signedHeaders := []SignedHeader{ + //{Name: "x-custom-header-a", Value: "test1"}, + //{Name: "x-custom-header-b", Value: "test2"}, + } + + body := []byte("{}") // Request body + + // Get current GMT time + gmtTime := time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT") + + // Dynamically construct the signing string (in order) + signingStringBuilder := strings.Builder{} + signingStringBuilder.WriteString(fmt.Sprintf("%s\n%s %s\ndate: %s\n", + keyID, + requestMethod, + requestPath, + gmtTime)) + + // Add headers in the order specified in signedHeaders + for _, header := range signedHeaders { + signingStringBuilder.WriteString(fmt.Sprintf("%s: %s\n", header.Name, header.Value)) + } + + signingString := signingStringBuilder.String() + + // Generate signature + signature, err := generateHmacSignature(secretKey, algorithm, signingString) + if err != nil { + fmt.Printf("Error generating signature: %v\n", err) + return + } + + // Dynamically build the content of the headers field + headersField := "@request-target date" + for _, header := range signedHeaders { + headersField += " " + header.Name + } + + // Construct request headers + headers := map[string]string{ + "Date": gmtTime, + "Authorization": fmt.Sprintf(`Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"`, + keyID, + algorithm, + headersField, + signature, + ), + } + + // Add Digest header if request body validation is required + if validateRequestBody { + headers["Digest"] = calculateBodyDigest(body) + } + + // Add signed request headers + for _, header := range signedHeaders { + formattedHeaderName := formatHeaderName(header.Name) + headers[formattedHeaderName] = header.Value + } + + // Print the signing string + fmt.Printf("signingString: %s\n", signingString) + // Print request headers + fmt.Println("Headers:") + for key, value := range headers { + fmt.Printf("%s: %s\n", key, value) + } +} + +// generateHmacSignature generates an HMAC signature +func generateHmacSignature(secretKey, algorithm, message string) (string, error) { + var mac hash.Hash + + switch algorithm { + case "hmac-sha1": + mac = hmac.New(sha1.New, []byte(secretKey)) + case "hmac-sha256": + mac = hmac.New(sha256.New, []byte(secretKey)) + case "hmac-sha512": + mac = hmac.New(sha512.New, []byte(secretKey)) + default: + return "", fmt.Errorf("unsupported algorithm: %s", algorithm) + } + + mac.Write([]byte(message)) + signature := mac.Sum(nil) + return base64.StdEncoding.EncodeToString(signature), nil +} + +// calculateBodyDigest calculates the digest of the request body +func calculateBodyDigest(body []byte) string { + hash := sha256.Sum256(body) + encodedDigest := base64.StdEncoding.EncodeToString(hash[:]) + return "SHA-256=" + encodedDigest +} + +// formatHeaderName converts the header name to standard HTTP header format +func formatHeaderName(headerName string) string { + parts := strings.Split(headerName, "-") + for i, part := range parts { + if len(part) > 0 { + parts[i] = strings.ToUpper(part[:1]) + strings.ToLower(part[1:]) + } + } + return strings.Join(parts, "-") +} +``` + + +#### Request and Response Examples: + +1. **Validation Passed Scenario** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="G2+60rCCHQCQDZOailnKHLCEy++P1Pa5OEP1bG4QlRo="' \ --H 'Date:Sat, 30 Aug 2025 00:52:39 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: Returns a normal response from the backend service. -- Additional Info: After successful authentication, the request header `X-Mse-Consumer: consumer1` is automatically added and passed to the backend. +``` +- **Response**: Returns a normal response from the backend service. +- **Additional Info**: After successful authentication, the request header `X-Mse-Consumer: consumer1` is automatically added and passed to the backend. 2. **Signature Verification Failure Due to Modified Request Method** ```shell -curl -X PUT 'http://localhost:8082/foo' \ # Changed from POST to PUT here --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="G2+60rCCHQCQDZOailnKHLCEy++P1Pa5OEP1bG4QlRo="' \ --H 'Date:Sat, 30 Aug 2025 00:52:39 GMT' \ +curl -X PUT 'http://localhost:8082/foo' \ # POST is modified to PUT here +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: `401 Unauthorized` -- Error Message: `{"message":"client request can't be validated: Invalid signature"}` +``` +- **Response**: `401 Unauthorized` +- **Error Message**: `{"message":"client request can't be validated: Invalid signature"}` -3. **Caller Not in the Allow List** +3. **Caller Not in Allow List** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer2-key",algorithm="hmac-sha256",headers="@request-target date",signature="5sqSbDX9b91dQsfQra2hpluM7O6/yhS7oLcKPQylyCo="' \ --H 'Date:Sat, 30 Aug 2025 00:54:18 GMT' \ +-H 'Authorization:Signature keyId="consumer2-key",algorithm="hmac-sha256",headers="@request-target date",signature="dltotPwd4iWGGz//kuehPJlHXZemR5WKwCPAJD/KPhE="' \ +-H 'Date:Fri, 12 Sep 2025 23:59:01 GMT' \ -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: `401 Unauthorized` -- Error Message: `{"message":"client request can't be validated: consumer 'consumer2' is not allowed"}` +``` +- **Response**: `401 Unauthorized` +- **Error Message**: `{"message":"client request can't be validated: consumer 'consumer2' is not allowed"}` 4. **Expired Timestamp** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization: Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="gvIUwoYNiK57w6xX2g1Ntpk8lfgD7z+jgom434r5qwg="' \ --H 'Date: Sat, 30 Aug 2025 00:40:21 GMT' \ # Expired timestamp +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date",signature="746z4VISwZehUwZdzTV486ZMMbBtakmMHKPfs/A4RdU="' \ +-H 'Date:Fri, 12 Sep 2025 23:53:18 GMT' \ # Expired timestamp -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: `401 Unauthorized` -- Error Message: `{"message":"client request can't be validated: Clock skew exceeded"}` +``` +- **Response**: `401 Unauthorized` +- **Error Message**: `{"message":"client request can't be validated: Clock skew exceeded"}` -#### Example 2: Configuration with Custom Signature Headers and Request Body Verification -**Instance-level Plugin Configuration**: +#### Example 2: Configuration with Custom Signed Headers and Request Body Validation + +**Instance-Level Plugin Configuration**: ```yaml global_auth: false consumers: @@ -150,56 +297,57 @@ signed_headers: # Custom request headers to be included in the signature - X-Custom-Header-A - X-Custom-Header-B validate_request_body: true # Enable request body signature verification -``` +``` -**Request and Response Examples**: +#### Request and Response Examples: -1. **Successful Verification Scenario** +1. **Validation Passed Scenario** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="+xCWYCmidq3Sisn08N54NWaau5vSY9qEanWoO9HD4mA="' \ --H 'Date:Sat, 30 Aug 2025 01:04:06 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="KoOlbkDIR/JzlKK47eURewnIpmhpkQU+KIyBUhqVfmo="' \ +-H 'Date:Sat, 13 Sep 2025 00:04:34 GMT' \ -H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ # Request body digest -H 'X-Custom-Header-A:test1' \ -H 'X-Custom-Header-B:test2' \ -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: Returns a normal response from the backend service. +``` +- **Response**: Returns a normal response from the backend service. -2. **Missing Signature Header** +2. **Missing Signed Header** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="+xCWYCmidq3Sisn08N54NWaau5vSY9qEanWoO9HD4mA="' \ --H 'Date:Sat, 30 Aug 2025 01:04:06 GMT' \ +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-b",signature="KoOlbkDIR/JzlKK47eURewnIpmhpkQU+KIyBUhqVfmo="' \ +-H 'Date:Sat, 13 Sep 2025 00:04:34 GMT' \ -H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ --H 'X-Custom-Header-B:test2' \ # Missing X-Custom-Header-A +-H 'X-Custom-Header-B:test2' \ # X-Custom-Header-A is missing -H 'Content-Type: application/json' \ -d '{}' -``` -- Response: `401 Unauthorized` -- Error Message: `{"message":"client request can't be validated: expected header \"X-Custom-Header-A\" missing in signing"}` +``` +- **Response**: `401 Unauthorized` +- **Error Message**: `{"message":"client request can't be validated: expected header \"X-Custom-Header-A\" missing in signing"}` 3. **Tampered Request Body** ```shell curl -X POST 'http://localhost:8082/foo' \ --H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="dSbv6pdQOcgkN89TmSxiT8F9nypbPUqAR2E7ELL8K2s="' \ --H 'Date:Sat, 30 Aug 2025 01:10:17 GMT' \ --H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ # Mismatches the actual body +-H 'Authorization:Signature keyId="consumer1-key",algorithm="hmac-sha256",headers="@request-target date x-custom-header-a x-custom-header-b",signature="NcA+44FFtl2rjNvV28wSn8Rln02i4i2tFXKp3/ahyYA="' \ +-H 'Date:Sat, 13 Sep 2025 00:09:40 GMT' \ +-H 'Digest:SHA-256=RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' \ -H 'X-Custom-Header-A:test1' \ -H 'X-Custom-Header-B:test2' \ -H 'Content-Type: application/json' \ -d '{"key":"value"}' # Tampered request body -``` -- Response: `401 Unauthorized` -- Error Message: `{"message":"client request can't be validated: Invalid digest"}` +``` +- **Response**: `401 Unauthorized` +- **Error Message**: `{"message":"client request can't be validated: Invalid digest"}` -### Enabling Global Authentication at the Gateway Instance Level -The following configuration enables HMAC Auth authentication at the gateway instance level. **All requests must pass authentication to access**: +### Enable Global Authentication at the Gateway Instance Level + +The following configuration enables Hmac Auth authentication at the gateway instance level. **All requests must be authenticated to access the gateway**: ```yaml global_auth: true # Enable global authentication @@ -210,6 +358,6 @@ consumers: - name: consumer2 access_key: consumer2-key secret_key: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35 -``` +``` -**Description**: When `global_auth: true`, all requests accessing the gateway must carry valid authentication information. Unauthenticated requests will be directly rejected. \ No newline at end of file +**Description**: When `global_auth: true`, all requests to the gateway must carry valid authentication information. Unauthenticated requests will be rejected directly. \ No newline at end of file