1
0
mirror of https://github.com/labstack/echo.git synced 2025-01-10 00:28:23 +02:00
echo/middleware/basic_auth.go

106 lines
2.9 KiB
Go
Raw Normal View History

package middleware
import (
2021-07-15 22:34:01 +02:00
"bytes"
"encoding/base64"
2021-07-15 22:34:01 +02:00
"errors"
"fmt"
2017-02-21 06:27:40 +02:00
"strconv"
"strings"
2021-07-15 22:34:01 +02:00
"github.com/labstack/echo/v5"
)
2021-07-15 22:34:01 +02:00
// BasicAuthConfig defines the config for BasicAuthWithConfig middleware.
type BasicAuthConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper
2021-07-15 22:34:01 +02:00
// Validator is a function to validate BasicAuthWithConfig credentials. Note: if request contains multiple basic auth headers
// this function would be called once for each header until first valid result is returned
// Required.
Validator BasicAuthValidator
2017-02-21 06:27:40 +02:00
2021-07-15 22:34:01 +02:00
// Realm is a string to define realm attribute of BasicAuthWithConfig.
// Default value "Restricted".
Realm string
}
2021-07-15 22:34:01 +02:00
// BasicAuthValidator defines a function to validate BasicAuthWithConfig credentials.
type BasicAuthValidator func(c echo.Context, user string, password string) (bool, error)
const (
basic = "basic"
2017-02-21 06:27:40 +02:00
defaultRealm = "Restricted"
)
// BasicAuth returns an BasicAuth middleware.
//
// For valid credentials it calls the next handler.
// For missing or invalid credentials, it sends "401 - Unauthorized" response.
func BasicAuth(fn BasicAuthValidator) echo.MiddlewareFunc {
2021-07-15 22:34:01 +02:00
return BasicAuthWithConfig(BasicAuthConfig{Validator: fn})
}
2021-07-15 22:34:01 +02:00
// BasicAuthWithConfig returns an BasicAuthWithConfig middleware with config.
func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
2021-07-15 22:34:01 +02:00
return toMiddlewareOrPanic(config)
}
// ToMiddleware converts BasicAuthConfig to middleware or returns an error for invalid configuration
func (config BasicAuthConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Validator == nil {
2021-07-15 22:34:01 +02:00
return nil, errors.New("echo basic-auth middleware requires a validator function")
}
if config.Skipper == nil {
2021-07-15 22:34:01 +02:00
config.Skipper = DefaultSkipper
}
2017-02-21 06:27:40 +02:00
if config.Realm == "" {
config.Realm = defaultRealm
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if config.Skipper(c) {
return next(c)
}
2021-07-15 22:34:01 +02:00
var lastError error
l := len(basic)
2021-07-15 22:34:01 +02:00
for _, auth := range c.Request().Header[echo.HeaderAuthorization] {
if !(len(auth) > l+1 && strings.EqualFold(auth[:l], basic)) {
continue
}
2021-07-15 22:34:01 +02:00
b, errDecode := base64.StdEncoding.DecodeString(auth[l+1:])
if errDecode != nil {
lastError = fmt.Errorf("invalid basic auth value: %w", errDecode)
continue
}
2021-07-15 22:34:01 +02:00
idx := bytes.IndexByte(b, ':')
if idx >= 0 {
valid, errValidate := config.Validator(c, string(b[:idx]), string(b[idx+1:]))
if errValidate != nil {
lastError = errValidate
} else if valid {
return next(c)
}
}
}
2021-07-15 22:34:01 +02:00
if lastError != nil {
return lastError
}
realm := defaultRealm
if config.Realm != defaultRealm {
2017-02-21 06:27:40 +02:00
realm = strconv.Quote(config.Realm)
}
// Need to return `401` for browsers to pop-up login box.
2017-02-21 06:27:40 +02:00
c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm="+realm)
return echo.ErrUnauthorized
}
2021-07-15 22:34:01 +02:00
}, nil
}