You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ro...@apache.org on 2025/10/30 04:09:16 UTC

(apisix-ingress-controller) branch feat/response-rewrite updated (908f1688 -> 2d1c7770)

This is an automated email from the ASF dual-hosted git repository.

ronething pushed a change to branch feat/response-rewrite
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


    from 908f1688 feat: support response rewrite annotations for ingress
     add 4cd10056 feat: support auth-type for ingress annotations (#2636)
     new 2d1c7770 Merge remote-tracking branch 'origin/master' into feat/response-rewrite

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../plugins/{csrf.go => authorization.go}          |  43 +++++---
 .../adc/translator/annotations/plugins/plugins.go  |   2 +
 internal/adc/translator/annotations_test.go        |  22 ++++
 test/e2e/ingress/annotations.go                    | 119 +++++++++++++++++++++
 4 files changed, 171 insertions(+), 15 deletions(-)
 copy internal/adc/translator/annotations/plugins/{csrf.go => authorization.go} (51%)


(apisix-ingress-controller) 01/01: Merge remote-tracking branch 'origin/master' into feat/response-rewrite

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ronething pushed a commit to branch feat/response-rewrite
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git

commit 2d1c77708778b08532a22614a27638f017493a44
Merge: 908f1688 4cd10056
Author: Ashing Zheng <ax...@gmail.com>
AuthorDate: Thu Oct 30 12:09:04 2025 +0800

    Merge remote-tracking branch 'origin/master' into feat/response-rewrite
    
    Signed-off-by: Ashing Zheng <ax...@gmail.com>

 .../annotations/plugins/authorization.go           |  61 +++++++++++
 .../adc/translator/annotations/plugins/plugins.go  |   2 +
 internal/adc/translator/annotations_test.go        |  22 ++++
 test/e2e/ingress/annotations.go                    | 119 +++++++++++++++++++++
 4 files changed, 204 insertions(+)

diff --cc internal/adc/translator/annotations/plugins/authorization.go
index 00000000,83b64c5b..2dee12ea
mode 000000,100644..100644
--- a/internal/adc/translator/annotations/plugins/authorization.go
+++ b/internal/adc/translator/annotations/plugins/authorization.go
@@@ -1,0 -1,61 +1,61 @@@
+ // Licensed to the Apache Software Foundation (ASF) under one or more
+ // contributor license agreements.  See the NOTICE file distributed with
+ // this work for additional information regarding copyright ownership.
+ // The ASF licenses this file to You 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
+ //
+ //	http://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 plugins
+ 
+ import (
+ 	adctypes "github.com/apache/apisix-ingress-controller/api/adc"
+ 	"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations"
+ )
+ 
+ type basicAuth struct{}
+ 
+ // NewkeyBasicHandler creates a handler to convert
+ // annotations about basicAuth control to APISIX basic-auth plugin.
+ func NewBasicAuthHandler() PluginAnnotationsHandler {
+ 	return &basicAuth{}
+ }
+ 
+ func (b *basicAuth) PluginName() string {
+ 	return "basic-auth"
+ }
+ 
 -func (b *basicAuth) Handle(e annotations.Extractor) (interface{}, error) {
++func (b *basicAuth) Handle(e annotations.Extractor) (any, error) {
+ 	if e.GetStringAnnotation(annotations.AnnotationsAuthType) != "basicAuth" {
+ 		return nil, nil
+ 	}
+ 	plugin := adctypes.BasicAuthConfig{}
+ 	return &plugin, nil
+ }
+ 
+ type keyAuth struct{}
+ 
+ // NewkeyAuthHandler creates a handler to convert
+ // annotations about keyAuth control to APISIX key-auth plugin.
+ func NewKeyAuthHandler() PluginAnnotationsHandler {
+ 	return &keyAuth{}
+ }
+ 
+ func (k *keyAuth) PluginName() string {
+ 	return "key-auth"
+ }
+ 
 -func (k *keyAuth) Handle(e annotations.Extractor) (interface{}, error) {
++func (k *keyAuth) Handle(e annotations.Extractor) (any, error) {
+ 	if e.GetStringAnnotation(annotations.AnnotationsAuthType) != "keyAuth" {
+ 		return nil, nil
+ 	}
+ 	plugin := adctypes.KeyAuthConfig{}
+ 	return &plugin, nil
+ }
diff --cc internal/adc/translator/annotations/plugins/plugins.go
index f49fe8f8,8ebb0fb3..a0cd78f8
--- a/internal/adc/translator/annotations/plugins/plugins.go
+++ b/internal/adc/translator/annotations/plugins/plugins.go
@@@ -40,7 -40,8 +40,9 @@@ var 
  		NewCorsHandler(),
  		NewCSRFHandler(),
  		NewFaultInjectionHandler(),
+ 		NewBasicAuthHandler(),
+ 		NewKeyAuthHandler(),
 +		NewResponseRewriteHandler(),
  	}
  )
  
diff --cc test/e2e/ingress/annotations.go
index 8683935e,f7a19a1f..a4e9e10d
--- a/test/e2e/ingress/annotations.go
+++ b/test/e2e/ingress/annotations.go
@@@ -382,57 -382,48 +382,99 @@@ spec
              name: httpbin-service-e2e-test
              port:
                number: 80
+ `
+ 			ingressKeyAuth = `
+ apiVersion: networking.k8s.io/v1
+ kind: Ingress
+ metadata:
+   name: key-auth
+   annotations:
+     k8s.apisix.apache.org/auth-type: "keyAuth"
+ spec:
+   ingressClassName: %s
+   rules:
+   - host: httpbin.example
+     http:
+       paths:
+       - path: /ip
+         pathType: Exact
+         backend:
+           service:
+             name: httpbin-service-e2e-test
+             port:
+               number: 80
+ `
+ 			ingressBasicAuth = `
+ apiVersion: networking.k8s.io/v1
+ kind: Ingress
+ metadata:
+   name: basic-auth
+   annotations:
+     k8s.apisix.apache.org/auth-type: "basicAuth"
+ spec:
+   ingressClassName: %s
+   rules:
+   - host: httpbin.example
+     http:
+       paths:
+       - path: /get
+         pathType: Exact
+         backend:
+           service:
+             name: httpbin-service-e2e-test
+             port:
+               number: 80
 +`
 +			responseRewrite = `
 +apiVersion: networking.k8s.io/v1
 +kind: Ingress
 +metadata:
 +  name: response-rewrite
 +  annotations:
 +    k8s.apisix.apache.org/enable-response-rewrite: "true"
 +    k8s.apisix.apache.org/response-rewrite-status-code: "400"
 +    k8s.apisix.apache.org/response-rewrite-body: "custom response body"
 +    k8s.apisix.apache.org/response-rewrite-body-base64: "false"
 +    k8s.apisix.apache.org/response-rewrite-set-header: "X-Custom-Header:custom-value"
 +    k8s.apisix.apache.org/response-rewrite-add-header: "X-Add-Header:added-value"
 +    k8s.apisix.apache.org/response-rewrite-remove-header: "Server"
 +spec:
 +  ingressClassName: %s
 +  rules:
 +  - host: httpbin.example
 +    http:
 +      paths:
 +      - path: /get
 +        pathType: Exact
 +        backend:
 +          service:
 +            name: httpbin-service-e2e-test
 +            port:
 +              number: 80
 +`
 +			responseRewriteBase64 = `
 +apiVersion: networking.k8s.io/v1
 +kind: Ingress
 +metadata:
 +  name: response-rewrite-base64
 +  annotations:
 +    k8s.apisix.apache.org/enable-response-rewrite: "true"
 +    k8s.apisix.apache.org/response-rewrite-status-code: "400"
 +    k8s.apisix.apache.org/response-rewrite-body: "Y3VzdG9tIHJlc3BvbnNlIGJvZHk="
 +    k8s.apisix.apache.org/response-rewrite-body-base64: "true"
 +spec:
 +  ingressClassName: %s
 +  rules:
 +  - host: httpbin-base64.example
 +    http:
 +      paths:
 +      - path: /get
 +        pathType: Exact
 +        backend:
 +          service:
 +            name: httpbin-service-e2e-test
 +            port:
 +              number: 80
  `
  		)
  		BeforeEach(func() {
@@@ -661,62 -652,82 +703,139 @@@ spec
  				s.RequestAssert(test)
  			}
  		})
+ 		It("authentication", func() {
+ 			var (
+ 				keyAuth = `
+ apiVersion: apisix.apache.org/v2
+ kind: ApisixConsumer
+ metadata:
+   name: key
+ spec:
+   ingressClassName: %s
+   authParameter:
+     keyAuth:
+       value:
+         key: test-key
+ `
+ 				basicAuth = `
+ apiVersion: apisix.apache.org/v2
+ kind: ApisixConsumer
+ metadata:
+   name: basic
+ spec:
+   ingressClassName: %s
+   authParameter:
+     basicAuth:
+       value:
+         username: test-user
+         password: test-password
+ `
+ 			)
+ 			Expect(s.CreateResourceFromString(fmt.Sprintf(keyAuth, s.Namespace()))).ShouldNot(HaveOccurred(), "creating ApisixConsumer for keyAuth")
+ 			Expect(s.CreateResourceFromString(fmt.Sprintf(basicAuth, s.Namespace()))).ShouldNot(HaveOccurred(), "creating ApisixConsumer for basicAuth")
+ 			Expect(s.CreateResourceFromString(fmt.Sprintf(ingressKeyAuth, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress")
+ 			Expect(s.CreateResourceFromString(fmt.Sprintf(ingressBasicAuth, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress")
+ 
+ 			tests := []*scaffold.RequestAssert{
+ 				{
+ 					Method: "GET",
+ 					Path:   "/get",
+ 					Host:   "httpbin.example",
+ 					BasicAuth: &scaffold.BasicAuth{
+ 						Username: "test-user",
+ 						Password: "test-password",
+ 					},
+ 					Check: scaffold.WithExpectedStatus(http.StatusOK),
+ 				},
+ 				{
+ 					Method: "GET",
+ 					Path:   "/get",
+ 					Host:   "httpbin.example",
+ 					BasicAuth: &scaffold.BasicAuth{
+ 						Username: "invalid-user",
+ 						Password: "invalid-password",
+ 					},
+ 					Check: scaffold.WithExpectedStatus(http.StatusUnauthorized),
+ 				},
+ 				{
+ 					Method: "GET",
+ 					Path:   "/ip",
+ 					Host:   "httpbin.example",
+ 					Headers: map[string]string{
+ 						"apikey": "test-key",
+ 					},
+ 					Check: scaffold.WithExpectedStatus(http.StatusOK),
+ 				},
+ 				{
+ 					Method: "GET",
+ 					Path:   "/ip",
+ 					Host:   "httpbin.example",
+ 					Headers: map[string]string{
+ 						"apikey": "invalid-key",
+ 					},
+ 					Check: scaffold.WithExpectedStatus(http.StatusUnauthorized),
+ 				},
+ 			}
+ 			for _, test := range tests {
+ 				s.RequestAssert(test)
+ 			}
+ 		})
 +
 +		It("response-rewrite", func() {
 +			Expect(s.CreateResourceFromString(fmt.Sprintf(responseRewrite, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress")
 +
 +			s.RequestAssert(&scaffold.RequestAssert{
 +				Method: "GET",
 +				Path:   "/get",
 +				Host:   "httpbin.example",
 +				Checks: []scaffold.ResponseCheckFunc{
 +					scaffold.WithExpectedStatus(http.StatusBadRequest),
 +					scaffold.WithExpectedBodyContains("custom response body"),
 +					scaffold.WithExpectedHeader("X-Custom-Header", "custom-value"),
 +					scaffold.WithExpectedHeader("X-Add-Header", "added-value"),
 +				},
 +			})
 +
 +			By("Verify response-rewrite plugin is configured in the route")
 +			routes, err := s.DefaultDataplaneResource().Route().List(context.Background())
 +			Expect(err).NotTo(HaveOccurred(), "listing Route")
 +			Expect(routes).To(HaveLen(1), "checking Route length")
 +			Expect(routes[0].Plugins).To(HaveKey("response-rewrite"), "checking Route plugins")
 +
 +			jsonBytes, err := json.Marshal(routes[0].Plugins["response-rewrite"])
 +			Expect(err).NotTo(HaveOccurred(), "marshalling response-rewrite plugin config")
 +			var rewriteConfig map[string]any
 +			err = json.Unmarshal(jsonBytes, &rewriteConfig)
 +			Expect(err).NotTo(HaveOccurred(), "unmarshalling response-rewrite plugin config")
 +			Expect(rewriteConfig["status_code"]).To(Equal(float64(400)), "checking status code")
 +			Expect(rewriteConfig["body"]).To(Equal("custom response body"), "checking body")
 +		})
 +
 +		It("response-rewrite with base64", func() {
 +			Expect(s.CreateResourceFromString(fmt.Sprintf(responseRewriteBase64, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress")
 +
 +			s.RequestAssert(&scaffold.RequestAssert{
 +				Method: "GET",
 +				Path:   "/get",
 +				Host:   "httpbin-base64.example",
 +				Checks: []scaffold.ResponseCheckFunc{
 +					scaffold.WithExpectedStatus(http.StatusBadRequest),
 +					scaffold.WithExpectedBodyContains("custom response body"),
 +				},
 +			})
 +			By("Verify response-rewrite plugin is configured in the route")
 +			routes, err := s.DefaultDataplaneResource().Route().List(context.Background())
 +			Expect(err).NotTo(HaveOccurred(), "listing Route")
 +			Expect(routes).To(HaveLen(1), "checking Route length")
 +			Expect(routes[0].Plugins).To(HaveKey("response-rewrite"), "checking Route plugins")
 +
 +			jsonBytes, err := json.Marshal(routes[0].Plugins["response-rewrite"])
 +			Expect(err).NotTo(HaveOccurred(), "marshalling response-rewrite plugin config")
 +			var rewriteConfig map[string]any
 +			err = json.Unmarshal(jsonBytes, &rewriteConfig)
 +			Expect(err).NotTo(HaveOccurred(), "unmarshalling response-rewrite plugin config")
 +			Expect(rewriteConfig["status_code"]).To(Equal(float64(400)), "checking status code")
 +			Expect(rewriteConfig["body_base64"]).To(BeTrue(), "checking body_base64")
 +		})
  	})
  })