summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/v4/middleware/jwt.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/v4/middleware/jwt.go')
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/jwt.go209
1 files changed, 81 insertions, 128 deletions
diff --git a/vendor/github.com/labstack/echo/v4/middleware/jwt.go b/vendor/github.com/labstack/echo/v4/middleware/jwt.go
index 21e33ab8..bec5167e 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/jwt.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/jwt.go
@@ -1,3 +1,4 @@
+//go:build go1.15
// +build go1.15
package middleware
@@ -5,12 +6,10 @@ package middleware
import (
"errors"
"fmt"
- "net/http"
- "reflect"
- "strings"
-
"github.com/golang-jwt/jwt"
"github.com/labstack/echo/v4"
+ "net/http"
+ "reflect"
)
type (
@@ -22,7 +21,8 @@ type (
// BeforeFunc defines a function which is executed just before the middleware.
BeforeFunc BeforeFunc
- // SuccessHandler defines a function which is executed for a valid token.
+ // SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
+ // middleware or handler.
SuccessHandler JWTSuccessHandler
// ErrorHandler defines a function which is executed for an invalid token.
@@ -32,6 +32,13 @@ type (
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
ErrorHandlerWithContext JWTErrorHandlerWithContext
+ // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
+ // ignore the error (by returning `nil`).
+ // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
+ // In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
+ // and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
+ ContinueOnIgnoredError bool
+
// Signing key to validate token.
// This is one of the three options to provide a token validation key.
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
@@ -61,16 +68,26 @@ type (
// to extract token from the request.
// Optional. Default value "header:Authorization".
// Possible values:
- // - "header:<name>"
+ // - "header:<name>" or "header:<name>:<cut-prefix>"
+ // `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
+ // value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
+ // want to cut is `<auth-scheme> ` note the space at the end.
+ // In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
+ // If prefix is left empty the whole value is returned.
// - "query:<name>"
// - "param:<name>"
// - "cookie:<name>"
// - "form:<name>"
- // Multiply sources example:
- // - "header: Authorization,cookie: myowncookie"
-
+ // Multiple sources example:
+ // - "header:Authorization,cookie:myowncookie"
TokenLookup string
+ // TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
+ // This is one of the two options to provide a token extractor.
+ // The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
+ // You can also provide both if you want.
+ TokenLookupFuncs []ValuesExtractor
+
// AuthScheme to be used in the Authorization header.
// Optional. Default value "Bearer".
AuthScheme string
@@ -95,15 +112,13 @@ type (
}
// JWTSuccessHandler defines a function which is executed for a valid token.
- JWTSuccessHandler func(echo.Context)
+ JWTSuccessHandler func(c echo.Context)
// JWTErrorHandler defines a function which is executed for an invalid token.
- JWTErrorHandler func(error) error
+ JWTErrorHandler func(err error) error
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
- JWTErrorHandlerWithContext func(error, echo.Context) error
-
- jwtExtractor func(echo.Context) (string, error)
+ JWTErrorHandlerWithContext func(err error, c echo.Context) error
)
// Algorithms
@@ -120,13 +135,14 @@ var (
var (
// DefaultJWTConfig is the default JWT auth middleware config.
DefaultJWTConfig = JWTConfig{
- Skipper: DefaultSkipper,
- SigningMethod: AlgorithmHS256,
- ContextKey: "user",
- TokenLookup: "header:" + echo.HeaderAuthorization,
- AuthScheme: "Bearer",
- Claims: jwt.MapClaims{},
- KeyFunc: nil,
+ Skipper: DefaultSkipper,
+ SigningMethod: AlgorithmHS256,
+ ContextKey: "user",
+ TokenLookup: "header:" + echo.HeaderAuthorization,
+ TokenLookupFuncs: nil,
+ AuthScheme: "Bearer",
+ Claims: jwt.MapClaims{},
+ KeyFunc: nil,
}
)
@@ -163,7 +179,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.Claims == nil {
config.Claims = DefaultJWTConfig.Claims
}
- if config.TokenLookup == "" {
+ if config.TokenLookup == "" && len(config.TokenLookupFuncs) == 0 {
config.TokenLookup = DefaultJWTConfig.TokenLookup
}
if config.AuthScheme == "" {
@@ -176,25 +192,12 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
config.ParseTokenFunc = config.defaultParseToken
}
- // Initialize
- // Split sources
- sources := strings.Split(config.TokenLookup, ",")
- var extractors []jwtExtractor
- for _, source := range sources {
- parts := strings.Split(source, ":")
-
- switch parts[0] {
- case "query":
- extractors = append(extractors, jwtFromQuery(parts[1]))
- case "param":
- extractors = append(extractors, jwtFromParam(parts[1]))
- case "cookie":
- extractors = append(extractors, jwtFromCookie(parts[1]))
- case "form":
- extractors = append(extractors, jwtFromForm(parts[1]))
- case "header":
- extractors = append(extractors, jwtFromHeader(parts[1], config.AuthScheme))
- }
+ extractors, err := createExtractors(config.TokenLookup, config.AuthScheme)
+ if err != nil {
+ panic(err)
+ }
+ if len(config.TokenLookupFuncs) > 0 {
+ extractors = append(config.TokenLookupFuncs, extractors...)
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
@@ -206,48 +209,54 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.BeforeFunc != nil {
config.BeforeFunc(c)
}
- var auth string
- var err error
+
+ var lastExtractorErr error
+ var lastTokenErr error
for _, extractor := range extractors {
- // Extract token from extractor, if it's not fail break the loop and
- // set auth
- auth, err = extractor(c)
- if err == nil {
- break
+ auths, err := extractor(c)
+ if err != nil {
+ lastExtractorErr = ErrJWTMissing // backwards compatibility: all extraction errors are same (unlike KeyAuth)
+ continue
}
- }
- // If none of extractor has a token, handle error
- if err != nil {
- if config.ErrorHandler != nil {
- return config.ErrorHandler(err)
- }
-
- if config.ErrorHandlerWithContext != nil {
- return config.ErrorHandlerWithContext(err, c)
+ for _, auth := range auths {
+ token, err := config.ParseTokenFunc(auth, c)
+ if err != nil {
+ lastTokenErr = err
+ continue
+ }
+ // Store user information from token into context.
+ c.Set(config.ContextKey, token)
+ if config.SuccessHandler != nil {
+ config.SuccessHandler(c)
+ }
+ return next(c)
}
- return err
}
-
- token, err := config.ParseTokenFunc(auth, c)
- if err == nil {
- // Store user information from token into context.
- c.Set(config.ContextKey, token)
- if config.SuccessHandler != nil {
- config.SuccessHandler(c)
- }
- return next(c)
+ // we are here only when we did not successfully extract or parse any of the tokens
+ err := lastTokenErr
+ if err == nil { // prioritize token errors over extracting errors
+ err = lastExtractorErr
}
if config.ErrorHandler != nil {
return config.ErrorHandler(err)
}
if config.ErrorHandlerWithContext != nil {
- return config.ErrorHandlerWithContext(err, c)
+ tmpErr := config.ErrorHandlerWithContext(err, c)
+ if config.ContinueOnIgnoredError && tmpErr == nil {
+ return next(c)
+ }
+ return tmpErr
}
- return &echo.HTTPError{
- Code: ErrJWTInvalid.Code,
- Message: ErrJWTInvalid.Message,
- Internal: err,
+
+ // backwards compatible errors codes
+ if lastTokenErr != nil {
+ return &echo.HTTPError{
+ Code: ErrJWTInvalid.Code,
+ Message: ErrJWTInvalid.Message,
+ Internal: err,
+ }
}
+ return err // this is lastExtractorErr value
}
}
}
@@ -289,59 +298,3 @@ func (config *JWTConfig) defaultKeyFunc(t *jwt.Token) (interface{}, error) {
return config.SigningKey, nil
}
-
-// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
-func jwtFromHeader(header string, authScheme string) jwtExtractor {
- return func(c echo.Context) (string, error) {
- auth := c.Request().Header.Get(header)
- l := len(authScheme)
- if len(auth) > l+1 && strings.EqualFold(auth[:l], authScheme) {
- return auth[l+1:], nil
- }
- return "", ErrJWTMissing
- }
-}
-
-// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
-func jwtFromQuery(param string) jwtExtractor {
- return func(c echo.Context) (string, error) {
- token := c.QueryParam(param)
- if token == "" {
- return "", ErrJWTMissing
- }
- return token, nil
- }
-}
-
-// jwtFromParam returns a `jwtExtractor` that extracts token from the url param string.
-func jwtFromParam(param string) jwtExtractor {
- return func(c echo.Context) (string, error) {
- token := c.Param(param)
- if token == "" {
- return "", ErrJWTMissing
- }
- return token, nil
- }
-}
-
-// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
-func jwtFromCookie(name string) jwtExtractor {
- return func(c echo.Context) (string, error) {
- cookie, err := c.Cookie(name)
- if err != nil {
- return "", ErrJWTMissing
- }
- return cookie.Value, nil
- }
-}
-
-// jwtFromForm returns a `jwtExtractor` that extracts token from the form field.
-func jwtFromForm(name string) jwtExtractor {
- return func(c echo.Context) (string, error) {
- field := c.FormValue(name)
- if field == "" {
- return "", ErrJWTMissing
- }
- return field, nil
- }
-}