fix(server): handled errors not logged correctly (#3507)

This fixes an issue where errors handled by the ErrorHandler were not correctly logged. It also ensures the errors are logged with fields to make them easy to diagnose.

Fixes #3506
This commit is contained in:
James Elliott 2022-06-12 09:26:28 +10:00 committed by GitHub
parent 6f8ec531e7
commit 5e3a1fd863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 18 deletions

View File

@ -1,6 +1,7 @@
package server package server
import ( import (
"fmt"
"net" "net"
"os" "os"
"strconv" "strconv"
@ -9,6 +10,7 @@ import (
duoapi "github.com/duosecurity/duo_api_golang" duoapi "github.com/duosecurity/duo_api_golang"
"github.com/fasthttp/router" "github.com/fasthttp/router"
"github.com/sirupsen/logrus"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/expvarhandler" "github.com/valyala/fasthttp/expvarhandler"
"github.com/valyala/fasthttp/pprofhandler" "github.com/valyala/fasthttp/pprofhandler"
@ -23,9 +25,7 @@ import (
) )
// Replacement for the default error handler in fasthttp. // Replacement for the default error handler in fasthttp.
func handlerError() func(ctx *fasthttp.RequestCtx, err error) { func handleError() func(ctx *fasthttp.RequestCtx, err error) {
logger := logging.Logger()
headerXForwardedFor := []byte(fasthttp.HeaderXForwardedFor) headerXForwardedFor := []byte(fasthttp.HeaderXForwardedFor)
getRemoteIP := func(ctx *fasthttp.RequestCtx) string { getRemoteIP := func(ctx *fasthttp.RequestCtx) string {
@ -41,26 +41,43 @@ func handlerError() func(ctx *fasthttp.RequestCtx, err error) {
} }
return func(ctx *fasthttp.RequestCtx, err error) { return func(ctx *fasthttp.RequestCtx, err error) {
var (
statusCode int
message string
)
switch e := err.(type) { switch e := err.(type) {
case *fasthttp.ErrSmallBuffer: case *fasthttp.ErrSmallBuffer:
logger.Tracef("Request was too large to handle from client %s. Response Code %d.", getRemoteIP(ctx), fasthttp.StatusRequestHeaderFieldsTooLarge) statusCode = fasthttp.StatusRequestHeaderFieldsTooLarge
ctx.Error("request header too large", fasthttp.StatusRequestHeaderFieldsTooLarge) message = "Request from client exceeded the server buffer sizes."
case *net.OpError: case *net.OpError:
if e.Timeout() { if e.Timeout() {
logger.Tracef("Request timeout occurred while handling from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusRequestTimeout) statusCode = fasthttp.StatusRequestTimeout
ctx.Error("request timeout", fasthttp.StatusRequestTimeout) message = "Request timeout occurred while handling request from client."
} else { } else {
logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusBadRequest) statusCode = fasthttp.StatusBadRequest
ctx.Error("error when parsing request", fasthttp.StatusBadRequest) message = "An unknown network error occurred while handling a request from client."
} }
default: default:
logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusBadRequest) statusCode = fasthttp.StatusBadRequest
ctx.Error("error when parsing request", fasthttp.StatusBadRequest) message = "An unknown error occurred while handling a request from client."
} }
logging.Logger().WithFields(logrus.Fields{
"method": string(ctx.Method()),
"path": string(ctx.Path()),
"remote_ip": getRemoteIP(ctx),
"status_code": statusCode,
}).WithError(err).Error(message)
ctx.Response.Reset()
ctx.SetStatusCode(statusCode)
ctx.SetContentType("text/plain; charset=utf-8")
ctx.SetBodyString(fmt.Sprintf("%d %s", statusCode, fasthttp.StatusMessage(statusCode)))
} }
} }
func handlerNotFound(next fasthttp.RequestHandler) fasthttp.RequestHandler { func handleNotFound(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) { return func(ctx *fasthttp.RequestCtx) {
path := strings.ToLower(string(ctx.Path())) path := strings.ToLower(string(ctx.Path()))
@ -76,11 +93,11 @@ func handlerNotFound(next fasthttp.RequestHandler) fasthttp.RequestHandler {
} }
} }
func handlerMethodNotAllowed(ctx *fasthttp.RequestCtx) { func handleMethodNotAllowed(ctx *fasthttp.RequestCtx) {
handlers.SetStatusCodeResponse(ctx, fasthttp.StatusMethodNotAllowed) handlers.SetStatusCodeResponse(ctx, fasthttp.StatusMethodNotAllowed)
} }
func getHandler(config schema.Configuration, providers middlewares.Providers) fasthttp.RequestHandler { func handleRouter(config schema.Configuration, providers middlewares.Providers) fasthttp.RequestHandler {
rememberMe := strconv.FormatBool(config.Session.RememberMeDuration != schema.RememberMeDisabled) rememberMe := strconv.FormatBool(config.Session.RememberMeDuration != schema.RememberMeDisabled)
resetPassword := strconv.FormatBool(!config.AuthenticationBackend.DisableResetPassword) resetPassword := strconv.FormatBool(!config.AuthenticationBackend.DisableResetPassword)
@ -307,10 +324,10 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST))))
} }
r.NotFound = handlerNotFound(middleware(serveIndexHandler)) r.NotFound = handleNotFound(middleware(serveIndexHandler))
r.HandleMethodNotAllowed = true r.HandleMethodNotAllowed = true
r.MethodNotAllowed = handlerMethodNotAllowed r.MethodNotAllowed = handleMethodNotAllowed
if config.Server.Path != "" { if config.Server.Path != "" {
return middlewares.StripPath(config.Server.Path)(middlewares.LogRequest(r.Handler)) return middlewares.StripPath(config.Server.Path)(middlewares.LogRequest(r.Handler))

View File

@ -17,8 +17,8 @@ import (
// CreateServer Create Authelia's internal webserver with the given configuration and providers. // CreateServer Create Authelia's internal webserver with the given configuration and providers.
func CreateServer(config schema.Configuration, providers middlewares.Providers) (*fasthttp.Server, net.Listener) { func CreateServer(config schema.Configuration, providers middlewares.Providers) (*fasthttp.Server, net.Listener) {
server := &fasthttp.Server{ server := &fasthttp.Server{
ErrorHandler: handlerError(), ErrorHandler: handleError(),
Handler: getHandler(config, providers), Handler: handleRouter(config, providers),
NoDefaultServerHeader: true, NoDefaultServerHeader: true,
ReadBufferSize: config.Server.ReadBufferSize, ReadBufferSize: config.Server.ReadBufferSize,
WriteBufferSize: config.Server.WriteBufferSize, WriteBufferSize: config.Server.WriteBufferSize,