feat(plugin): implement golang version of plugin jwt-auth (#743)

Signed-off-by: Ink33 <Ink33@smlk.org>
This commit is contained in:
Ink33
2024-06-06 10:22:51 +08:00
committed by GitHub
parent 6a40d83ec0
commit ed976c6d06
24 changed files with 2713 additions and 1 deletions

View File

@@ -0,0 +1,146 @@
// Copyright (c) 2023 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 handler
import (
"net/url"
"strings"
cfg "github.com/alibaba/higress/plugins/wasm-go/extensions/jwt-auth/config"
)
// extracToken 从三个来源中依次尝试抽取Token若找不到Token则返回空字符串
func extractToken(keepToken bool, consumer *cfg.Consumer, header HeaderProvider, log Logger) string {
token := ""
// 1. 从header中抽取token
if h := consumer.FromHeaders; h != nil {
token = extractFromHeader(keepToken, *h, header, log)
}
if token != "" {
return token
}
// 2. 从params中抽取token
if p := consumer.FromParams; p != nil {
token = extractFromParams(keepToken, *p, header, log)
}
if token != "" {
return token
}
// 3. 从cookies中抽取token
if c := consumer.FromCookies; c != nil {
token = extractFromCookies(keepToken, *c, header, log)
}
// 此处无需判空
return token
}
func extractFromHeader(keepToken bool, headers []cfg.FromHeader, header HeaderProvider, log Logger) (token string) {
for i := range headers {
// proxywasm 获取到的 header name 均为小写,此处需做修改
lowerName := strings.ToLower(headers[i].Name)
token, err := header.GetHttpRequestHeader(lowerName)
if err != nil {
log.Warnf("failed to get authorization: %v", err)
continue
}
if token != "" {
if !strings.HasPrefix(token, headers[i].ValuePrefix) {
log.Warnf("authorization has no prefix %q", headers[i].ValuePrefix)
return ""
}
if !keepToken {
_ = header.RemoveHttpRequestHeader(lowerName)
}
return strings.TrimPrefix(token, headers[i].ValuePrefix)
}
}
return ""
}
func extractFromParams(keepToken bool, params []string, header HeaderProvider, log Logger) (token string) {
urlparams, err := header.GetHttpRequestHeader(":path")
if err != nil {
log.Warnf("failed to get authorization: %v", err)
return ""
}
url, _ := url.Parse(urlparams)
query := url.Query()
for i := range params {
token := query.Get(params[i])
if token != "" {
if !keepToken {
query.Del(params[i])
}
return token
}
}
return ""
}
func extractFromCookies(keepToken bool, cookies []string, header HeaderProvider, log Logger) (token string) {
requestCookies, err := header.GetHttpRequestHeader("cookie")
if err != nil {
log.Warnf("failed to get authorization: %v", err)
return ""
}
for i := range cookies {
token := findCookie(requestCookies, cookies[i])
if token != "" {
if !keepToken {
_ = header.ReplaceHttpRequestHeader("cookie", deleteCookie(requestCookies, cookies[i]))
}
return token
}
}
return ""
}
func findCookie(cookie string, key string) string {
value := ""
pairs := strings.Split(cookie, ";")
for _, pair := range pairs {
pair = strings.TrimSpace(pair)
kv := strings.Split(pair, "=")
if kv[0] == key {
value = kv[1]
break
}
}
return value
}
func deleteCookie(cookie string, key string) string {
result := ""
pairs := strings.Split(cookie, ";")
for _, pair := range pairs {
pair = strings.TrimSpace(pair)
if !strings.HasPrefix(pair, key) {
result += pair + ";"
}
}
return strings.TrimSuffix(result, ";")
}