mirror of
https://github.com/zap-proto/fiber.git
synced 2026-10-30 15:06:23 +00:00
Fork of gofiber/fiber v3 based on the v3.2.0 tag. Rewrites all self-imports github.com/gofiber/fiber/v3 -> github.com/zap-proto/fiber/v3. Upstream gofiber/schema and gofiber/utils/v2 dependencies are left untouched. Co-authored-by: Hanzo Dev <[email protected]>
175 lines
4.8 KiB
Go
175 lines
4.8 KiB
Go
package keyauth
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/zap-proto/fiber/v3"
|
|
"github.com/zap-proto/fiber/v3/extractors"
|
|
)
|
|
|
|
const (
|
|
ErrorInvalidRequest = "invalid_request"
|
|
ErrorInvalidToken = "invalid_token"
|
|
ErrorInsufficientScope = "insufficient_scope"
|
|
)
|
|
|
|
// Config defines the config for middleware.
|
|
type Config struct {
|
|
// Next defines a function to skip this middleware when returned true.
|
|
//
|
|
// Optional. Default: nil
|
|
Next func(c fiber.Ctx) bool
|
|
|
|
// SuccessHandler defines a function which is executed for a valid key.
|
|
//
|
|
// Optional. Default: c.Next()
|
|
SuccessHandler fiber.Handler
|
|
|
|
// ErrorHandler defines a function which is executed for an invalid key.
|
|
// It may be used to define a custom error.
|
|
//
|
|
// Optional. Default: 401 Missing or invalid API Key
|
|
ErrorHandler fiber.ErrorHandler
|
|
|
|
// Validator is a function to validate the key.
|
|
//
|
|
// Required.
|
|
Validator func(c fiber.Ctx, key string) (bool, error)
|
|
|
|
// Realm defines the protected area for WWW-Authenticate responses.
|
|
// This is used to set the `WWW-Authenticate` header when authentication fails.
|
|
//
|
|
// Optional. Default value "Restricted".
|
|
Realm string
|
|
|
|
// Challenge defines the full `WWW-Authenticate` header value used when
|
|
// the middleware responds with 401 and no Authorization scheme is
|
|
// present.
|
|
//
|
|
// Optional. Default: `ApiKey realm="<Realm>"` when no Authorization scheme
|
|
// is configured.
|
|
Challenge string
|
|
|
|
// Error is the RFC 6750 `error` parameter appended to Bearer
|
|
// `WWW-Authenticate` challenges when validation fails. Allowed values
|
|
// are `invalid_request`, `invalid_token`, or `insufficient_scope`.
|
|
//
|
|
// Optional. Default: "".
|
|
Error string
|
|
|
|
// ErrorDescription is the RFC 6750 `error_description` parameter
|
|
// appended to Bearer `WWW-Authenticate` challenges when validation
|
|
// fails. This field requires that `Error` is also set.
|
|
//
|
|
// Optional. Default: "".
|
|
ErrorDescription string
|
|
|
|
// ErrorURI is the RFC 6750 `error_uri` parameter appended to Bearer
|
|
// `WWW-Authenticate` challenges when validation fails. This field
|
|
// requires that `Error` is also set.
|
|
//
|
|
// Optional. Default: "".
|
|
ErrorURI string
|
|
|
|
// Scope is the RFC 6750 `scope` parameter appended to Bearer
|
|
// challenges when the `error` is `insufficient_scope`. This field
|
|
// requires that `Error` is set to `insufficient_scope`.
|
|
//
|
|
// Optional. Default: "".
|
|
Scope string
|
|
|
|
// Extractor is a function to extract the key from the request.
|
|
//
|
|
// Optional. Default: extractors.FromAuthHeader("Bearer")
|
|
Extractor extractors.Extractor
|
|
}
|
|
|
|
// ConfigDefault is the default config
|
|
var ConfigDefault = Config{
|
|
SuccessHandler: func(c fiber.Ctx) error {
|
|
return c.Next()
|
|
},
|
|
ErrorHandler: func(c fiber.Ctx, _ error) error {
|
|
return c.Status(fiber.StatusUnauthorized).SendString(ErrMissingOrMalformedAPIKey.Error())
|
|
},
|
|
Realm: "Restricted",
|
|
Extractor: extractors.FromAuthHeader("Bearer"),
|
|
}
|
|
|
|
// configDefault is a helper function to set default values
|
|
func configDefault(config ...Config) Config {
|
|
// Return default config if nothing provided
|
|
if len(config) < 1 {
|
|
panic("fiber: keyauth middleware requires a validator function")
|
|
}
|
|
cfg := config[0]
|
|
|
|
// Require a validator function
|
|
if cfg.Validator == nil {
|
|
panic("fiber: keyauth middleware requires a validator function")
|
|
}
|
|
|
|
// Set default values
|
|
if cfg.Extractor.Extract == nil {
|
|
cfg.Extractor = ConfigDefault.Extractor
|
|
}
|
|
if cfg.Realm == "" {
|
|
cfg.Realm = ConfigDefault.Realm
|
|
}
|
|
if cfg.SuccessHandler == nil {
|
|
cfg.SuccessHandler = ConfigDefault.SuccessHandler
|
|
}
|
|
if cfg.ErrorHandler == nil {
|
|
cfg.ErrorHandler = ConfigDefault.ErrorHandler
|
|
}
|
|
|
|
if len(getAuthSchemes(cfg.Extractor)) == 0 && cfg.Challenge == "" {
|
|
cfg.Challenge = fmt.Sprintf("ApiKey realm=%q", cfg.Realm)
|
|
}
|
|
|
|
if cfg.Error != "" {
|
|
switch cfg.Error {
|
|
case ErrorInvalidRequest, ErrorInvalidToken, ErrorInsufficientScope:
|
|
default:
|
|
panic("fiber: keyauth unsupported error token")
|
|
}
|
|
}
|
|
if cfg.ErrorDescription != "" && cfg.Error == "" {
|
|
panic("fiber: keyauth error_description requires error")
|
|
}
|
|
if cfg.ErrorURI != "" {
|
|
if cfg.Error == "" {
|
|
panic("fiber: keyauth error_uri requires error")
|
|
}
|
|
if u, err := url.Parse(cfg.ErrorURI); err != nil || !u.IsAbs() {
|
|
panic("fiber: keyauth error_uri must be absolute")
|
|
}
|
|
}
|
|
if cfg.Error == ErrorInsufficientScope {
|
|
if cfg.Scope == "" {
|
|
panic("fiber: keyauth insufficient_scope requires scope")
|
|
}
|
|
for scope := range strings.SplitSeq(cfg.Scope, " ") {
|
|
if scope == "" || !isScopeToken(scope) {
|
|
panic("fiber: keyauth scope contains invalid token")
|
|
}
|
|
}
|
|
} else if cfg.Scope != "" {
|
|
panic("fiber: keyauth scope requires insufficient_scope error")
|
|
}
|
|
|
|
return cfg
|
|
}
|
|
|
|
func isScopeToken(s string) bool {
|
|
for i := 0; i < len(s); i++ {
|
|
c := s[i]
|
|
if c < 0x21 || c > 0x7e || c == '"' || c == '\\' {
|
|
return false
|
|
}
|
|
}
|
|
return s != ""
|
|
}
|