mirror of
https://github.com/alibaba/higress.git
synced 2026-06-26 02:35:02 +08:00
remove basic-auth useless annotation (#1779)
This commit is contained in:
@@ -15,12 +15,6 @@
|
|||||||
package annotations
|
package annotations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
||||||
. "github.com/alibaba/higress/pkg/ingress/log"
|
. "github.com/alibaba/higress/pkg/ingress/log"
|
||||||
)
|
)
|
||||||
@@ -57,101 +51,10 @@ func (a auth) Parse(annotations Annotations, config *Ingress, globalContext *Glo
|
|||||||
if !needAuthConfig(annotations) {
|
if !needAuthConfig(annotations) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
IngressLog.Error("The annotation nginx.ingress.kubernetes.io/auth-type is no longer supported after version 2.0.0, please use the higress wasm plugin (e.g., basic-auth) as an alternative.")
|
||||||
authConfig := &AuthConfig{
|
|
||||||
AuthType: defaultAuthType,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check auth type
|
|
||||||
authType, err := annotations.ParseStringASAP(authType)
|
|
||||||
if err != nil {
|
|
||||||
IngressLog.Errorf("Parse auth type error %v within ingress %/%s", err, config.Namespace, config.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if authType != defaultAuthType {
|
|
||||||
IngressLog.Errorf("Auth type %s within ingress %/%s is not supported yet.", authType, config.Namespace, config.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
secretName, _ := annotations.ParseStringASAP(authSecretAnn)
|
|
||||||
namespaced := util.SplitNamespacedName(secretName)
|
|
||||||
if namespaced.Name == "" {
|
|
||||||
IngressLog.Errorf("Auth secret name within ingress %s/%s is invalid", config.Namespace, config.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if namespaced.Namespace == "" {
|
|
||||||
namespaced.Namespace = config.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
configKey := util.ClusterNamespacedName{
|
|
||||||
NamespacedName: namespaced,
|
|
||||||
ClusterId: config.ClusterId,
|
|
||||||
}
|
|
||||||
authConfig.AuthSecret = configKey
|
|
||||||
|
|
||||||
// Subscribe secret
|
|
||||||
globalContext.WatchedSecrets.Insert(configKey.String())
|
|
||||||
|
|
||||||
secretType := authFileAuthSecretType
|
|
||||||
if rawSecretType, err := annotations.ParseStringASAP(authSecretTypeAnn); err == nil {
|
|
||||||
resultAuthSecretType := authSecretType(rawSecretType)
|
|
||||||
if resultAuthSecretType == authFileAuthSecretType || resultAuthSecretType == authMapAuthSecretType {
|
|
||||||
secretType = resultAuthSecretType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
authConfig.AuthRealm, _ = annotations.ParseStringASAP(authRealm)
|
|
||||||
|
|
||||||
// Process credentials.
|
|
||||||
secretLister, exist := globalContext.ClusterSecretLister[config.ClusterId]
|
|
||||||
if !exist {
|
|
||||||
IngressLog.Errorf("secret lister of cluster %s doesn't exist", config.ClusterId)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
authSecret, err := secretLister.Secrets(namespaced.Namespace).Get(namespaced.Name)
|
|
||||||
if err != nil {
|
|
||||||
IngressLog.Errorf("Secret %s within ingress %s/%s is not found",
|
|
||||||
namespaced.String(), config.Namespace, config.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
credentials, err := convertCredentials(secretType, authSecret)
|
|
||||||
if err != nil {
|
|
||||||
IngressLog.Errorf("Parse auth secret fail, err %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
authConfig.Credentials = credentials
|
|
||||||
|
|
||||||
config.Auth = authConfig
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertCredentials(secretType authSecretType, secret *corev1.Secret) ([]string, error) {
|
|
||||||
var result []string
|
|
||||||
switch secretType {
|
|
||||||
case authFileAuthSecretType:
|
|
||||||
users, exist := secret.Data[authFileKey]
|
|
||||||
if !exist {
|
|
||||||
return nil, errors.New("the auth file type must has auth key in secret data")
|
|
||||||
}
|
|
||||||
userList := strings.Split(string(users), "\n")
|
|
||||||
for _, item := range userList {
|
|
||||||
if !strings.Contains(item, ":") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, item)
|
|
||||||
}
|
|
||||||
case authMapAuthSecretType:
|
|
||||||
for name, password := range secret.Data {
|
|
||||||
result = append(result, name+":"+string(password))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.SliceStable(result, func(i, j int) bool {
|
|
||||||
return result[i] < result[j]
|
|
||||||
})
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func needAuthConfig(annotations Annotations) bool {
|
func needAuthConfig(annotations Annotations) bool {
|
||||||
return annotations.HasASAP(authType) &&
|
return annotations.HasASAP(authType) &&
|
||||||
annotations.HasASAP(authSecretAnn)
|
annotations.HasASAP(authSecretAnn)
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
|
||||||
//
|
|
||||||
// Licensed 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 (
|
|
||||||
"context"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"istio.io/istio/pkg/cluster"
|
|
||||||
"istio.io/istio/pkg/util/sets"
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/client-go/informers"
|
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
|
||||||
listerv1 "k8s.io/client-go/listers/core/v1"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
|
|
||||||
"github.com/alibaba/higress/pkg/ingress/kube/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAuthParse(t *testing.T) {
|
|
||||||
auth := auth{}
|
|
||||||
inputCases := []struct {
|
|
||||||
input map[string]string
|
|
||||||
secret *v1.Secret
|
|
||||||
expect *AuthConfig
|
|
||||||
watchedSecret string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
secret: &v1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Namespace: "foo",
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"auth": []byte("A:a\nB:b"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{
|
|
||||||
buildNginxAnnotationKey(authType): "digest",
|
|
||||||
},
|
|
||||||
expect: nil,
|
|
||||||
secret: &v1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Namespace: "foo",
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"auth": []byte("A:a\nB:b"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{
|
|
||||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
|
||||||
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
|
|
||||||
},
|
|
||||||
secret: &v1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Namespace: "foo",
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"auth": []byte("A:a\nB:b"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expect: &AuthConfig{
|
|
||||||
AuthType: defaultAuthType,
|
|
||||||
AuthSecret: util.ClusterNamespacedName{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Namespace: "foo",
|
|
||||||
Name: "bar",
|
|
||||||
},
|
|
||||||
ClusterId: "cluster",
|
|
||||||
},
|
|
||||||
Credentials: []string{"A:a", "B:b"},
|
|
||||||
},
|
|
||||||
watchedSecret: "cluster/foo/bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{
|
|
||||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
|
||||||
buildHigressAnnotationKey(authSecretAnn): "foo/bar",
|
|
||||||
buildNginxAnnotationKey(authSecretTypeAnn): string(authMapAuthSecretType),
|
|
||||||
},
|
|
||||||
secret: &v1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Namespace: "foo",
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"A": []byte("a"),
|
|
||||||
"B": []byte("b"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expect: &AuthConfig{
|
|
||||||
AuthType: defaultAuthType,
|
|
||||||
AuthSecret: util.ClusterNamespacedName{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Namespace: "foo",
|
|
||||||
Name: "bar",
|
|
||||||
},
|
|
||||||
ClusterId: "cluster",
|
|
||||||
},
|
|
||||||
Credentials: []string{"A:a", "B:b"},
|
|
||||||
},
|
|
||||||
watchedSecret: "cluster/foo/bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{
|
|
||||||
buildNginxAnnotationKey(authType): defaultAuthType,
|
|
||||||
buildHigressAnnotationKey(authSecretAnn): "bar",
|
|
||||||
buildNginxAnnotationKey(authSecretTypeAnn): string(authFileAuthSecretType),
|
|
||||||
},
|
|
||||||
secret: &v1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "bar",
|
|
||||||
Namespace: "default",
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"auth": []byte("A:a\nB:b"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expect: &AuthConfig{
|
|
||||||
AuthType: defaultAuthType,
|
|
||||||
AuthSecret: util.ClusterNamespacedName{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Namespace: "default",
|
|
||||||
Name: "bar",
|
|
||||||
},
|
|
||||||
ClusterId: "cluster",
|
|
||||||
},
|
|
||||||
Credentials: []string{"A:a", "B:b"},
|
|
||||||
},
|
|
||||||
watchedSecret: "cluster/default/bar",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, inputCase := range inputCases {
|
|
||||||
t.Run("", func(t *testing.T) {
|
|
||||||
config := &Ingress{
|
|
||||||
Meta: Meta{
|
|
||||||
Namespace: "default",
|
|
||||||
ClusterId: "cluster",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
globalContext, cancel := initGlobalContext(inputCase.secret)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
_ = auth.Parse(inputCase.input, config, globalContext)
|
|
||||||
if !reflect.DeepEqual(inputCase.expect, config.Auth) {
|
|
||||||
t.Fatal("Should be equal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if inputCase.watchedSecret != "" {
|
|
||||||
if !globalContext.WatchedSecrets.Contains(inputCase.watchedSecret) {
|
|
||||||
t.Fatalf("Should watch secret %s", inputCase.watchedSecret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func initGlobalContext(secret *v1.Secret) (*GlobalContext, context.CancelFunc) {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
client := fake.NewSimpleClientset(secret)
|
|
||||||
informerFactory := informers.NewSharedInformerFactory(client, time.Hour)
|
|
||||||
secretInformer := informerFactory.Core().V1().Secrets()
|
|
||||||
go secretInformer.Informer().Run(ctx.Done())
|
|
||||||
cache.WaitForCacheSync(ctx.Done(), secretInformer.Informer().HasSynced)
|
|
||||||
|
|
||||||
return &GlobalContext{
|
|
||||||
WatchedSecrets: sets.New[string](),
|
|
||||||
ClusterSecretLister: map[cluster.ID]listerv1.SecretLister{
|
|
||||||
"cluster": secretInformer.Lister(),
|
|
||||||
},
|
|
||||||
}, cancel
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user