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

zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 670d671d feat:add authorization-annotation the ingress resource (#985)
670d671d is described below

commit 670d671d436701ec8083248c6b23713a50ec0c4c
Author: Xin Rong <[email protected]>
AuthorDate: Wed May 11 11:26:11 2022 +0800

    feat:add authorization-annotation the ingress resource (#985)
---
 pkg/kube/translation/annotations.go               |   2 +
 pkg/kube/translation/annotations/authorization.go |  64 +++++
 pkg/types/apisix/v1/plugin_types.go               |  10 +
 pkg/types/apisix/v1/zz_generated.deepcopy.go      |  32 +++
 test/e2e/scaffold/consumer.go                     |  26 +-
 test/e2e/suite-annotations/authorization.go       | 310 ++++++++++++++++++++++
 6 files changed, 441 insertions(+), 3 deletions(-)

diff --git a/pkg/kube/translation/annotations.go 
b/pkg/kube/translation/annotations.go
index 767f7da0..3f06b813 100644
--- a/pkg/kube/translation/annotations.go
+++ b/pkg/kube/translation/annotations.go
@@ -29,6 +29,8 @@ var (
                annotations.NewRewriteHandler(),
                annotations.NewRedirectHandler(),
                annotations.NewForwardAuthHandler(),
+               annotations.NewBasicAuthHandler(),
+               annotations.NewKeyAuthHandler(),
        }
 )
 
diff --git a/pkg/kube/translation/annotations/authorization.go 
b/pkg/kube/translation/annotations/authorization.go
new file mode 100644
index 00000000..c97567a4
--- /dev/null
+++ b/pkg/kube/translation/annotations/authorization.go
@@ -0,0 +1,64 @@
+// 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 annotations
+
+import (
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+const (
+       // auth-type: keyAuth | basicAuth
+       _authType = AnnotationsPrefix + "auth-type"
+)
+
+type basicAuth struct{}
+
+// NewkeyBasicHandler creates a handler to convert
+// annotations about basicAuth control to APISIX basic-auth plugin.
+func NewBasicAuthHandler() Handler {
+       return &basicAuth{}
+}
+
+func (b *basicAuth) PluginName() string {
+       return "basic-auth"
+}
+
+func (b *basicAuth) Handle(e Extractor) (interface{}, error) {
+       if e.GetStringAnnotation(_authType) != "basicAuth" {
+               return nil, nil
+       }
+       plugin := apisixv1.BasicAuthConfig{}
+       return &plugin, nil
+}
+
+type keyAuth struct{}
+
+// NewkeyAuthHandler creates a handler to convert
+// annotations about keyAuth control to APISIX key-auth plugin.
+func NewKeyAuthHandler() Handler {
+       return &keyAuth{}
+}
+
+func (k *keyAuth) PluginName() string {
+       return "key-auth"
+}
+
+func (k *keyAuth) Handle(e Extractor) (interface{}, error) {
+       if e.GetStringAnnotation(_authType) != "keyAuth" {
+               return nil, nil
+       }
+       plugin := apisixv1.KeyAuthConfig{}
+       return &plugin, nil
+}
diff --git a/pkg/types/apisix/v1/plugin_types.go 
b/pkg/types/apisix/v1/plugin_types.go
index 51346b78..b0f927c9 100644
--- a/pkg/types/apisix/v1/plugin_types.go
+++ b/pkg/types/apisix/v1/plugin_types.go
@@ -99,3 +99,13 @@ type ForwardAuthConfig struct {
        UpstreamHeaders []string `json:"upstream_headers,omitempty"`
        ClientHeaders   []string `json:"client_headers,omitempty"`
 }
+
+// BasicAuthConfig is the rule config for basic-auth plugin.
+// +k8s:deepcopy-gen=true
+type BasicAuthConfig struct {
+}
+
+// KeyAuthConfig is the rule config for key-auth plugin.
+// +k8s:deepcopy-gen=true
+type KeyAuthConfig struct {
+}
diff --git a/pkg/types/apisix/v1/zz_generated.deepcopy.go 
b/pkg/types/apisix/v1/zz_generated.deepcopy.go
index eabfe8b9..4016a713 100644
--- a/pkg/types/apisix/v1/zz_generated.deepcopy.go
+++ b/pkg/types/apisix/v1/zz_generated.deepcopy.go
@@ -19,6 +19,22 @@
 
 package v1
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *BasicAuthConfig) DeepCopyInto(out *BasicAuthConfig) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new BasicAuthConfig.
+func (in *BasicAuthConfig) DeepCopy() *BasicAuthConfig {
+       if in == nil {
+               return nil
+       }
+       out := new(BasicAuthConfig)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *BasicAuthConsumerConfig) DeepCopyInto(out *BasicAuthConsumerConfig) {
        *out = *in
@@ -165,6 +181,22 @@ func (in *IPRestrictConfig) DeepCopy() *IPRestrictConfig {
        return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *KeyAuthConfig) DeepCopyInto(out *KeyAuthConfig) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new KeyAuthConfig.
+func (in *KeyAuthConfig) DeepCopy() *KeyAuthConfig {
+       if in == nil {
+               return nil
+       }
+       out := new(KeyAuthConfig)
+       in.DeepCopyInto(out)
+       return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *KeyAuthConsumerConfig) DeepCopyInto(out *KeyAuthConsumerConfig) {
        *out = *in
diff --git a/test/e2e/scaffold/consumer.go b/test/e2e/scaffold/consumer.go
index 3c44a7c7..5cee9b24 100644
--- a/test/e2e/scaffold/consumer.go
+++ b/test/e2e/scaffold/consumer.go
@@ -16,8 +16,8 @@ package scaffold
 
 import "fmt"
 
-func (s *Scaffold) ApisixConsumerBasicAuthCreated(name, username, password 
string) error {
-       ac := fmt.Sprintf(`
+var (
+       _apisixConsumerBasicAuth = `
 apiVersion: apisix.apache.org/v2beta3
 kind: ApisixConsumer
 metadata:
@@ -28,6 +28,26 @@ spec:
       value:
         username: %s
         password: %s
-`, name, username, password)
+`
+       _apisixConsumerKeyAuth = `
+  apiVersion: apisix.apache.org/v2beta3
+  kind: ApisixConsumer
+  metadata:
+    name: %s
+  spec:
+    authParameter:
+      keyAuth:
+        value:
+          key: %s
+  `
+)
+
+func (s *Scaffold) ApisixConsumerBasicAuthCreated(name, username, password 
string) error {
+       ac := fmt.Sprintf(_apisixConsumerBasicAuth, name, username, password)
+       return s.CreateResourceFromString(ac)
+}
+
+func (s *Scaffold) ApisixConsumerKeyAuthCreated(name, key string) error {
+       ac := fmt.Sprintf(_apisixConsumerKeyAuth, name, key)
        return s.CreateResourceFromString(ac)
 }
diff --git a/test/e2e/suite-annotations/authorization.go 
b/test/e2e/suite-annotations/authorization.go
new file mode 100644
index 00000000..d1818651
--- /dev/null
+++ b/test/e2e/suite-annotations/authorization.go
@@ -0,0 +1,310 @@
+// 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 annotations
+
+import (
+       "fmt"
+       "net/http"
+       "time"
+
+       "github.com/onsi/ginkgo"
+       "github.com/stretchr/testify/assert"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("suite-annotations: authorization annotations", func() 
{
+       s := scaffold.NewDefaultScaffold()
+
+       ginkgo.It("enable keyAuth in ingress networking/v1", func() {
+               err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "keyAuth"
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          service:
+            name: %s
+            port:
+              number: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key 
found in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("apikey", "bar").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+
+       ginkgo.It("enable keyAuth in ingress networking/v1beta1", func() {
+               err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "keyAuth"
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key 
found in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("apikey", "bar").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+
+       ginkgo.It("enable keyAuth in ingress extensions/v1beta1", func() {
+               err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "keyAuth"
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key 
found in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("apikey", "bar").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+
+       ginkgo.It("enable basicAuth in ingress networking/v1", func() {
+               err := s.ApisixConsumerBasicAuthCreated("jack1", 
"jack1-username", "jack1-password")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "basicAuth"
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          service:
+            name: %s
+            port:
+              number: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing 
authorization in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("Authorization", "Basic 
amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+
+       ginkgo.It("enable basicAuth in ingress networking/v1beta1", func() {
+               err := s.ApisixConsumerBasicAuthCreated("jack1", 
"jack1-username", "jack1-password")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "basicAuth"
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing 
authorization in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("Authorization", "Basic 
amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+
+       ginkgo.It("enable basicAuth in ingress networking/v1beta1", func() {
+               err := s.ApisixConsumerBasicAuthCreated("jack1", 
"jack1-username", "jack1-password")
+               assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth 
ApisixConsumer")
+
+               // Wait until the ApisixConsumer create event was delivered.
+               time.Sleep(6 * time.Second)
+
+               backendSvc, backendPort := s.DefaultHTTPBackend()
+               ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/auth-type: "basicAuth"
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+               err = s.CreateResourceFromString(ing)
+               assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+               time.Sleep(5 * time.Second)
+
+               msg401 := s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       Expect().
+                       Status(http.StatusUnauthorized).
+                       Body().
+                       Raw()
+               assert.Contains(ginkgo.GinkgoT(), msg401, "Missing 
authorization in request")
+
+               _ = s.NewAPISIXClient().GET("/ip").
+                       WithHeader("Host", "httpbin.org").
+                       WithHeader("Authorization", "Basic 
amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+                       Expect().
+                       Status(http.StatusOK)
+       })
+})

Reply via email to