Files
gluetun/internal/server/middlewares/auth/middleware.go

67 lines
1.7 KiB
Go
Raw Normal View History

package auth
import (
"fmt"
"net/http"
)
func New(settings Settings, debugLogger DebugLogger) (
middleware func(http.Handler) http.Handler,
2024-10-11 19:20:48 +00:00
err error,
) {
routeToRoles, err := settingsToLookupMap(settings)
if err != nil {
return nil, fmt.Errorf("converting settings to lookup maps: %w", err)
}
return func(handler http.Handler) http.Handler {
return &authHandler{
childHandler: handler,
routeToRoles: routeToRoles,
logger: debugLogger,
}
}, nil
}
type authHandler struct {
childHandler http.Handler
routeToRoles map[string][]internalRole
logger DebugLogger
}
func (h *authHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
route := request.Method + " " + request.URL.Path
roles := h.routeToRoles[route]
if len(roles) == 0 {
h.logger.Debugf("no authentication role defined for route %s", route)
http.Error(writer, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
responseHeader := make(http.Header, 0)
for _, role := range roles {
if !role.checker.isAuthorized(responseHeader, request) {
continue
}
h.logger.Debugf("access to route %s authorized for role %s", route, role.name)
h.childHandler.ServeHTTP(writer, request)
return
}
// Flush out response headers if all roles failed to authenticate
for headerKey, headerValues := range responseHeader {
for _, headerValue := range headerValues {
writer.Header().Add(headerKey, headerValue)
}
}
allRoleNames := make([]string, len(roles))
for i, role := range roles {
allRoleNames[i] = role.name
}
h.logger.Debugf("access to route %s unauthorized after checking for roles %s",
route, andStrings(allRoleNames))
http.Error(writer, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}