mirror of
https://github.com/alibaba/higress.git
synced 2026-05-26 05:37:25 +08:00
feat: support ext_auth wasmplugin (#1103)
This commit is contained in:
229
plugins/wasm-go/extensions/ext-auth/config.go
Normal file
229
plugins/wasm-go/extensions/ext-auth/config.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"ext-auth/expr"
|
||||
"fmt"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
|
||||
"github.com/tidwall/gjson"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultStatusOnError uint32 = http.StatusForbidden
|
||||
|
||||
DefaultHttpServiceTimeout uint32 = 200
|
||||
)
|
||||
|
||||
type ExtAuthConfig struct {
|
||||
httpService HttpService
|
||||
failureModeAllow bool
|
||||
failureModeAllowHeaderAdd bool
|
||||
statusOnError uint32
|
||||
}
|
||||
|
||||
type HttpService struct {
|
||||
client wrapper.HttpClient
|
||||
requestMethod string
|
||||
path string
|
||||
timeout uint32
|
||||
authorizationRequest AuthorizationRequest
|
||||
authorizationResponse AuthorizationResponse
|
||||
}
|
||||
|
||||
type AuthorizationRequest struct {
|
||||
// allowedHeaders In addition to the user’s supplied matchers,
|
||||
// Host, Method, Path, Content-Length, and Authorization are automatically included to the list.
|
||||
allowedHeaders expr.Matcher
|
||||
headersToAdd map[string]string
|
||||
withRequestBody bool
|
||||
}
|
||||
|
||||
type AuthorizationResponse struct {
|
||||
allowedUpstreamHeaders expr.Matcher
|
||||
allowedClientHeaders expr.Matcher
|
||||
}
|
||||
|
||||
func parseConfig(json gjson.Result, config *ExtAuthConfig, log wrapper.Log) error {
|
||||
httpServiceConfig := json.Get("http_service")
|
||||
if !httpServiceConfig.Exists() {
|
||||
return errors.New("missing http_service in config")
|
||||
}
|
||||
err := parseHttpServiceConfig(httpServiceConfig, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
failureModeAllow := json.Get("failure_mode_allow")
|
||||
if failureModeAllow.Exists() {
|
||||
config.failureModeAllow = failureModeAllow.Bool()
|
||||
}
|
||||
|
||||
failureModeAllowHeaderAdd := json.Get("failure_mode_allow_header_add")
|
||||
if failureModeAllowHeaderAdd.Exists() {
|
||||
config.failureModeAllowHeaderAdd = failureModeAllowHeaderAdd.Bool()
|
||||
}
|
||||
|
||||
statusOnError := json.Get("status_on_error")
|
||||
if statusOnError.Exists() {
|
||||
config.statusOnError = uint32(statusOnError.Uint())
|
||||
} else {
|
||||
config.statusOnError = DefaultStatusOnError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseHttpServiceConfig(json gjson.Result, config *ExtAuthConfig) error {
|
||||
var httpService HttpService
|
||||
|
||||
if err := parseEndpointConfig(json, &httpService); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeout := uint32(json.Get("timeout").Uint())
|
||||
if timeout == 0 {
|
||||
timeout = DefaultHttpServiceTimeout
|
||||
}
|
||||
httpService.timeout = timeout
|
||||
|
||||
if err := parseAuthorizationRequestConfig(json, &httpService); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := parseAuthorizationResponseConfig(json, &httpService); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.httpService = httpService
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseEndpointConfig(json gjson.Result, httpService *HttpService) error {
|
||||
endpointConfig := json.Get("endpoint")
|
||||
if !endpointConfig.Exists() {
|
||||
return errors.New("missing endpoint in config")
|
||||
}
|
||||
|
||||
serviceSource := endpointConfig.Get("service_source").String()
|
||||
serviceName := endpointConfig.Get("service_name").String()
|
||||
servicePort := endpointConfig.Get("service_port").Int()
|
||||
if serviceName == "" || servicePort == 0 {
|
||||
return errors.New("invalid service config")
|
||||
}
|
||||
switch serviceSource {
|
||||
case "k8s":
|
||||
namespace := json.Get("namespace").String()
|
||||
httpService.client = wrapper.NewClusterClient(wrapper.K8sCluster{
|
||||
ServiceName: serviceName,
|
||||
Namespace: namespace,
|
||||
Port: servicePort,
|
||||
})
|
||||
return nil
|
||||
case "nacos":
|
||||
namespace := json.Get("namespace").String()
|
||||
httpService.client = wrapper.NewClusterClient(wrapper.NacosCluster{
|
||||
ServiceName: serviceName,
|
||||
NamespaceID: namespace,
|
||||
Port: servicePort,
|
||||
})
|
||||
return nil
|
||||
case "ip":
|
||||
httpService.client = wrapper.NewClusterClient(wrapper.StaticIpCluster{
|
||||
ServiceName: serviceName,
|
||||
Port: servicePort,
|
||||
})
|
||||
case "dns":
|
||||
domain := endpointConfig.Get("domain").String()
|
||||
httpService.client = wrapper.NewClusterClient(wrapper.DnsCluster{
|
||||
ServiceName: serviceName,
|
||||
Port: servicePort,
|
||||
Domain: domain,
|
||||
})
|
||||
default:
|
||||
return errors.New("unknown service source: " + serviceSource)
|
||||
}
|
||||
|
||||
requestMethodConfig := endpointConfig.Get("request_method")
|
||||
if !requestMethodConfig.Exists() {
|
||||
httpService.requestMethod = http.MethodGet
|
||||
} else {
|
||||
httpService.requestMethod = strings.ToUpper(requestMethodConfig.String())
|
||||
}
|
||||
|
||||
pathConfig := endpointConfig.Get("path")
|
||||
if !pathConfig.Exists() {
|
||||
return errors.New("missing path in config")
|
||||
}
|
||||
httpService.path = pathConfig.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseAuthorizationRequestConfig(json gjson.Result, httpService *HttpService) error {
|
||||
authorizationRequestConfig := json.Get("authorization_request")
|
||||
if authorizationRequestConfig.Exists() {
|
||||
var authorizationRequest AuthorizationRequest
|
||||
|
||||
headersToAdd := map[string]string{}
|
||||
headersToAddConfig := authorizationRequestConfig.Get("headers_to_add")
|
||||
if headersToAddConfig.Exists() {
|
||||
for key, value := range headersToAddConfig.Map() {
|
||||
headersToAdd[key] = value.Str
|
||||
}
|
||||
}
|
||||
authorizationRequest.headersToAdd = headersToAdd
|
||||
|
||||
withRequestBody := authorizationRequestConfig.Get("with_request_body")
|
||||
if withRequestBody.Exists() {
|
||||
// withRequestBody is true and the request method is GET, OPTIONS or HEAD
|
||||
if withRequestBody.Bool() &&
|
||||
(httpService.requestMethod == http.MethodGet || httpService.requestMethod == http.MethodOptions || httpService.requestMethod == http.MethodHead) {
|
||||
return errors.New(fmt.Sprintf("requestMethod %s does not support with_request_body set to true", httpService.requestMethod))
|
||||
}
|
||||
authorizationRequest.withRequestBody = withRequestBody.Bool()
|
||||
}
|
||||
|
||||
allowedHeaders := authorizationRequestConfig.Get("allowed_headers")
|
||||
if allowedHeaders.Exists() {
|
||||
result, err := expr.BuildRepeatedStringMatcherIgnoreCase(allowedHeaders.Array())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorizationRequest.allowedHeaders = result
|
||||
}
|
||||
|
||||
httpService.authorizationRequest = authorizationRequest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseAuthorizationResponseConfig(json gjson.Result, httpService *HttpService) error {
|
||||
authorizationResponseConfig := json.Get("authorization_response")
|
||||
if authorizationResponseConfig.Exists() {
|
||||
var authorizationResponse AuthorizationResponse
|
||||
|
||||
allowedUpstreamHeaders := authorizationResponseConfig.Get("allowed_upstream_headers")
|
||||
if allowedUpstreamHeaders.Exists() {
|
||||
result, err := expr.BuildRepeatedStringMatcherIgnoreCase(allowedUpstreamHeaders.Array())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorizationResponse.allowedUpstreamHeaders = result
|
||||
}
|
||||
|
||||
allowedClientHeaders := authorizationResponseConfig.Get("allowed_client_headers")
|
||||
if allowedClientHeaders.Exists() {
|
||||
result, err := expr.BuildRepeatedStringMatcherIgnoreCase(allowedClientHeaders.Array())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorizationResponse.allowedClientHeaders = result
|
||||
}
|
||||
|
||||
httpService.authorizationResponse = authorizationResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user