67 lines
1.7 KiB
Go
67 lines
1.7 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
func New(settings Settings, debugLogger DebugLogger) (
|
|
middleware func(http.Handler) http.Handler,
|
|
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)
|
|
}
|