fix(server): missing cache and xss headers (#3289)

Addresses documentation and a couple of headers which were missed.
This commit is contained in:
James Elliott 2022-05-04 14:47:23 +10:00 committed by GitHub
parent cac8919f97
commit 0855ea2f71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 172 additions and 124 deletions

View File

@ -89,10 +89,15 @@ that users who have access to the database do not also have access to this key.
The encrypted data in the database is as follows: The encrypted data in the database is as follows:
| Table | Column | Rational | | Table | Column | Rational |
|:-------------------:|:----------:|:------------------------------------------------------------------------------------------------------:| |:---------------------------------:|:------------:|:------------------------------------------------------------------------------------------------------:|
| totp_configurations | secret | Prevents a [Leaked Database](#leaked-database) or [Bad Actors](#bad-actors) from compromising security | | totp_configurations | secret | Prevents a [Leaked Database](#leaked-database) or [Bad Actors](#bad-actors) from compromising security |
| webauthn_devices | public_key | Prevents [Bad Actors](#bad-actors) from compromising security | | webauthn_devices | public_key | Prevents [Bad Actors](#bad-actors) from compromising security |
| oauth2_authorization_code_session | session_data | Prevents [Bad Actors](#bad-actors) from compromising security |
| oauth2_access_token_session | session_data | Prevents [Bad Actors](#bad-actors) from compromising security |
| oauth2_refresh_token_session | session_data | Prevents [Bad Actors](#bad-actors) from compromising security |
| oauth2_pkce_request_session | session_data | Prevents [Bad Actors](#bad-actors) from compromising security |
| oauth2_openid_connect_session | session_data | Prevents [Bad Actors](#bad-actors) from compromising security |
### Leaked Database ### Leaked Database
@ -224,77 +229,70 @@ feature, and set the [expiration](../configuration/session/index.md#expiration)
manner would mean if the cookie age was more than 2 hours or if the user was inactive for more than 10 minutes the manner would mean if the cookie age was more than 2 hours or if the user was inactive for more than 10 minutes the
session would be destroyed. session would be destroyed.
### Additional proxy protection measures ### Response Headers
You can also apply the following headers to your proxy configuration for improving security. Please read the This document previously detailed additional per-proxy configuration options that could be utilized in a proxy to
relevant documentation for these headers before applying them blindly. improve security. These headers are now documented here and implemented by default in all responses due to the fact
the experience should be the same regardless of which proxy you're utilizing and the area is rapidly evolving.
#### nginx Users who need custom behaviours in this area can submit a request or remove/replace the headers as necessary.
``` #### X-Content-Type-Options
# We don't want any credentials / TOTP secret key / QR code to be cached by
# the client
add_header Cache-Control "no-store";
add_header Pragma "no-cache";
# Clickjacking / XSS protection **Value:** `nosniff`
**Endpoints:** All
# We don't want Authelia's login page to be rendered within a <frame>, Prevents MIME type sniffing. See the
# <iframe> or <object> from an external website. [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options) for more information.
add_header X-Frame-Options "SAMEORIGIN";
# Block pages from loading when they detect reflected XSS attacks. #### Referrer-Policy
add_header X-XSS-Protection "1; mode=block";
```
**Value:** `strict-origin-when-cross-origin`
**Endpoints:** All
#### Traefik 2.x - Kubernetes CRD Sends only the origin as the referrer in cross-origin requests, but sends the origin, path, and query string in
same-origin requests. See the
[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) for more information.
```yaml #### X-Frame-Options
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: headers-authelia
spec:
headers:
browserXssFilter: true
customFrameOptionsValue: "SAMEORIGIN"
customResponseHeaders:
Cache-Control: "no-store"
Pragma: "no-cache"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: authelia
spec:
entryPoints:
- http
routes:
- match: Host(`auth.example.com`) && PathPrefix(`/`)
kind: Rule
priority: 1
middlewares:
- name: headers-authelia
namespace: authelia
services:
- name: authelia
port: 80
```
#### Traefik 2.x - docker-compose **Value:** `SAMEORIGIN`
**Endpoints:** All
```yaml Prevents Authelia rendering in a `frame`, `iframe`, `embed`, or `object` element. See the
services: [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) for more information.
authelia:
labels: #### X-XSS-Protection
- "traefik.http.routers.authelia.middlewares=authelia-headers"
- "traefik.http.middlewares.authelia-headers.headers.browserXssFilter=true" **Value:** `0`
- "traefik.http.middlewares.authelia-headers.headers.customFrameOptionsValue=SAMEORIGIN" **Endpoints:** All
- "traefik.http.middlewares.authelia-headers.headers.customResponseHeaders.Cache-Control=no-store"
- "traefik.http.middlewares.authelia-headers.headers.customResponseHeaders.Pragma=no-cache" We disable this as this feature is not present in any modern browser and could introduce vulnerabilities if enabled at
``` all. Going forward [CORS], [CORP], CORB, and [COEP] are the standards for browser centric site security. See the
[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection) for more information.
#### Permissions-Policy
**Value:** `interest-cohort=()`
**Endpoints:** All
Disables FLoC Cohorts.
#### Pragma
**Value:** `no-cache`
**Endpoints:** API
Disables caching of API requests on HTTP/1.0 browsers. See the
[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Pragma) for more information.
#### Cache-Control
**Value:** `no-store`
**Endpoints:** API
Disables caching responses entirely on HTTP/1.1 browsers. See the
[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) for more information.
### More protections measures with fail2ban ### More protections measures with fail2ban
@ -438,3 +436,6 @@ services:
``` ```
[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ [HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
[CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[CORP]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)
[COEP]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy

View File

@ -41,9 +41,9 @@ func NewAutheliaCtx(ctx *fasthttp.RequestCtx, configuration schema.Configuration
} }
// AutheliaMiddleware is wrapping the RequestCtx into an AutheliaCtx providing Authelia related objects. // AutheliaMiddleware is wrapping the RequestCtx into an AutheliaCtx providing Authelia related objects.
func AutheliaMiddleware(configuration schema.Configuration, providers Providers) RequestHandlerBridge { func AutheliaMiddleware(configuration schema.Configuration, providers Providers, middlewares ...StandardMiddleware) RequestHandlerBridge {
return func(next RequestHandler) fasthttp.RequestHandler { return func(next RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) { bridge := func(ctx *fasthttp.RequestCtx) {
autheliaCtx, err := NewAutheliaCtx(ctx, configuration, providers) autheliaCtx, err := NewAutheliaCtx(ctx, configuration, providers)
if err != nil { if err != nil {
autheliaCtx.Error(err, messageOperationFailed) autheliaCtx.Error(err, messageOperationFailed)
@ -52,6 +52,12 @@ func AutheliaMiddleware(configuration schema.Configuration, providers Providers)
next(autheliaCtx) next(autheliaCtx)
} }
for i := len(middlewares) - 1; i >= 0; i-- {
bridge = middlewares[i](bridge)
}
return bridge
} }
} }

View File

@ -31,9 +31,15 @@ var (
headerAccessControlRequestHeaders = []byte(fasthttp.HeaderAccessControlRequestHeaders) headerAccessControlRequestHeaders = []byte(fasthttp.HeaderAccessControlRequestHeaders)
headerAccessControlRequestMethod = []byte(fasthttp.HeaderAccessControlRequestMethod) headerAccessControlRequestMethod = []byte(fasthttp.HeaderAccessControlRequestMethod)
headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions) headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions)
headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy) headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy)
headerPermissionsPolicy = []byte("Permissions-Policy") headerXFrameOptions = []byte(fasthttp.HeaderXFrameOptions)
headerPragma = []byte(fasthttp.HeaderPragma)
headerCacheControl = []byte(fasthttp.HeaderCacheControl)
headerXXSSProtection = []byte(fasthttp.HeaderXXSSProtection)
headerContentSecurityPolicy = []byte(fasthttp.HeaderContentSecurityPolicy)
headerPermissionsPolicy = []byte("Permissions-Policy")
) )
var ( var (
@ -44,9 +50,14 @@ var (
headerValueVaryWildcard = []byte("Accept-Encoding") headerValueVaryWildcard = []byte("Accept-Encoding")
headerValueOriginWildcard = []byte("*") headerValueOriginWildcard = []byte("*")
headerValueZero = []byte("0") headerValueZero = []byte("0")
headerValueCSPNone = []byte("default-src 'none';")
headerValueNoSniff = []byte("nosniff") headerValueNoSniff = []byte("nosniff")
headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin") headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin")
headerValueSameOrigin = []byte("SAMEORIGIN")
headerValueNoCache = []byte("no-cache")
headerValueNoStore = []byte("no-store")
headerValueXSSModeBlock = []byte("1; mode=block")
headerValueCohort = []byte("interest-cohort=()") headerValueCohort = []byte("interest-cohort=()")
) )

View File

@ -10,6 +10,27 @@ func SecurityHeaders(next fasthttp.RequestHandler) fasthttp.RequestHandler {
ctx.Response.Header.SetBytesKV(headerXContentTypeOptions, headerValueNoSniff) ctx.Response.Header.SetBytesKV(headerXContentTypeOptions, headerValueNoSniff)
ctx.Response.Header.SetBytesKV(headerReferrerPolicy, headerValueStrictOriginCrossOrigin) ctx.Response.Header.SetBytesKV(headerReferrerPolicy, headerValueStrictOriginCrossOrigin)
ctx.Response.Header.SetBytesKV(headerPermissionsPolicy, headerValueCohort) ctx.Response.Header.SetBytesKV(headerPermissionsPolicy, headerValueCohort)
ctx.Response.Header.SetBytesKV(headerXFrameOptions, headerValueSameOrigin)
ctx.Response.Header.SetBytesKV(headerXXSSProtection, headerValueXSSModeBlock)
next(ctx)
}
}
// SecurityHeadersCSPNone middleware adds the Content-Security-Policy header with the value "default-src 'none';".
func SecurityHeadersCSPNone(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.Response.Header.SetBytesKV(headerContentSecurityPolicy, headerValueCSPNone)
next(ctx)
}
}
// SecurityHeadersNoStore middleware adds the Pragma no-cache and Cache-Control no-store headers.
func SecurityHeadersNoStore(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
ctx.Response.Header.SetBytesKV(headerPragma, headerValueNoCache)
ctx.Response.Header.SetBytesKV(headerCacheControl, headerValueNoStore)
next(ctx) next(ctx)
} }

View File

@ -7,17 +7,19 @@ import (
) )
// StripPath strips the first level of a path. // StripPath strips the first level of a path.
func StripPath(path string, next fasthttp.RequestHandler) fasthttp.RequestHandler { func StripPath(path string) (middleware StandardMiddleware) {
return func(ctx *fasthttp.RequestCtx) { return func(next fasthttp.RequestHandler) fasthttp.RequestHandler {
uri := ctx.RequestURI() return func(ctx *fasthttp.RequestCtx) {
uri := ctx.RequestURI()
if strings.HasPrefix(string(uri), path) { if strings.HasPrefix(string(uri), path) {
ctx.SetUserValueBytes(UserValueKeyBaseURL, path) ctx.SetUserValueBytes(UserValueKeyBaseURL, path)
newURI := strings.TrimPrefix(string(uri), path) newURI := strings.TrimPrefix(string(uri), path)
ctx.Request.SetRequestURI(newURI) ctx.Request.SetRequestURI(newURI)
}
next(ctx)
} }
next(ctx)
} }
} }

View File

@ -48,6 +48,9 @@ type RequestHandler = func(*AutheliaCtx)
// Middleware represent an Authelia middleware. // Middleware represent an Authelia middleware.
type Middleware = func(RequestHandler) RequestHandler type Middleware = func(RequestHandler) RequestHandler
// StandardMiddleware represents a fasthttp middleware.
type StandardMiddleware = func(next fasthttp.RequestHandler) (handler fasthttp.RequestHandler)
// RequestHandlerBridge bridge a AutheliaCtx handle to a RequestHandler handler. // RequestHandlerBridge bridge a AutheliaCtx handle to a RequestHandler handler.
type RequestHandlerBridge = func(RequestHandler) fasthttp.RequestHandler type RequestHandlerBridge = func(RequestHandler) fasthttp.RequestHandler

View File

@ -100,7 +100,7 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
handlerPublicHTML := newPublicHTMLEmbeddedHandler() handlerPublicHTML := newPublicHTMLEmbeddedHandler()
handlerLocales := newLocalesEmbeddedHandler() handlerLocales := newLocalesEmbeddedHandler()
middleware := middlewares.AutheliaMiddleware(config, providers) middleware := middlewares.AutheliaMiddleware(config, providers, middlewares.SecurityHeaders)
policyCORSPublicGET := middlewares.NewCORSPolicyBuilder(). policyCORSPublicGET := middlewares.NewCORSPolicyBuilder().
WithAllowedMethods("OPTIONS", "GET"). WithAllowedMethods("OPTIONS", "GET").
@ -134,53 +134,58 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
r.GET("/api/"+file, handlerPublicHTML) r.GET("/api/"+file, handlerPublicHTML)
} }
r.GET("/api/health", middleware(handlers.HealthGET)) middlewareAPI := middlewares.AutheliaMiddleware(
r.GET("/api/state", middleware(handlers.StateGET)) config, providers,
middlewares.SecurityHeaders, middlewares.SecurityHeadersNoStore, middlewares.SecurityHeadersCSPNone,
)
r.GET("/api/configuration", middleware(middlewares.Require1FA(handlers.ConfigurationGET))) r.GET("/api/health", middlewareAPI(handlers.HealthGET))
r.GET("/api/state", middlewareAPI(handlers.StateGET))
r.GET("/api/configuration/password-policy", middleware(handlers.PasswordPolicyConfigurationGet)) r.GET("/api/configuration", middlewareAPI(middlewares.Require1FA(handlers.ConfigurationGET)))
r.GET("/api/verify", middleware(handlers.VerifyGET(config.AuthenticationBackend))) r.GET("/api/configuration/password-policy", middlewareAPI(handlers.PasswordPolicyConfigurationGet))
r.HEAD("/api/verify", middleware(handlers.VerifyGET(config.AuthenticationBackend)))
r.POST("/api/checks/safe-redirection", middleware(handlers.CheckSafeRedirectionPOST)) r.GET("/api/verify", middlewareAPI(handlers.VerifyGET(config.AuthenticationBackend)))
r.HEAD("/api/verify", middlewareAPI(handlers.VerifyGET(config.AuthenticationBackend)))
r.POST("/api/checks/safe-redirection", middlewareAPI(handlers.CheckSafeRedirectionPOST))
delayFunc := middlewares.TimingAttackDelay(10, 250, 85, time.Second) delayFunc := middlewares.TimingAttackDelay(10, 250, 85, time.Second)
r.POST("/api/firstfactor", middleware(handlers.FirstFactorPOST(delayFunc))) r.POST("/api/firstfactor", middlewareAPI(handlers.FirstFactorPOST(delayFunc)))
r.POST("/api/logout", middleware(handlers.LogoutPOST)) r.POST("/api/logout", middlewareAPI(handlers.LogoutPOST))
// Only register endpoints if forgot password is not disabled. // Only register endpoints if forgot password is not disabled.
if !config.AuthenticationBackend.DisableResetPassword && if !config.AuthenticationBackend.DisableResetPassword &&
config.AuthenticationBackend.PasswordReset.CustomURL.String() == "" { config.AuthenticationBackend.PasswordReset.CustomURL.String() == "" {
// Password reset related endpoints. // Password reset related endpoints.
r.POST("/api/reset-password/identity/start", middleware(handlers.ResetPasswordIdentityStart)) r.POST("/api/reset-password/identity/start", middlewareAPI(handlers.ResetPasswordIdentityStart))
r.POST("/api/reset-password/identity/finish", middleware(handlers.ResetPasswordIdentityFinish)) r.POST("/api/reset-password/identity/finish", middlewareAPI(handlers.ResetPasswordIdentityFinish))
r.POST("/api/reset-password", middleware(handlers.ResetPasswordPOST)) r.POST("/api/reset-password", middlewareAPI(handlers.ResetPasswordPOST))
} }
// Information about the user. // Information about the user.
r.GET("/api/user/info", middleware(middlewares.Require1FA(handlers.UserInfoGET))) r.GET("/api/user/info", middlewareAPI(middlewares.Require1FA(handlers.UserInfoGET)))
r.POST("/api/user/info", middleware(middlewares.Require1FA(handlers.UserInfoPOST))) r.POST("/api/user/info", middlewareAPI(middlewares.Require1FA(handlers.UserInfoPOST)))
r.POST("/api/user/info/2fa_method", middleware(middlewares.Require1FA(handlers.MethodPreferencePOST))) r.POST("/api/user/info/2fa_method", middlewareAPI(middlewares.Require1FA(handlers.MethodPreferencePOST)))
if !config.TOTP.Disable { if !config.TOTP.Disable {
// TOTP related endpoints. // TOTP related endpoints.
r.GET("/api/user/info/totp", middleware(middlewares.Require1FA(handlers.UserTOTPInfoGET))) r.GET("/api/user/info/totp", middlewareAPI(middlewares.Require1FA(handlers.UserTOTPInfoGET)))
r.POST("/api/secondfactor/totp/identity/start", middleware(middlewares.Require1FA(handlers.TOTPIdentityStart))) r.POST("/api/secondfactor/totp/identity/start", middlewareAPI(middlewares.Require1FA(handlers.TOTPIdentityStart)))
r.POST("/api/secondfactor/totp/identity/finish", middleware(middlewares.Require1FA(handlers.TOTPIdentityFinish))) r.POST("/api/secondfactor/totp/identity/finish", middlewareAPI(middlewares.Require1FA(handlers.TOTPIdentityFinish)))
r.POST("/api/secondfactor/totp", middleware(middlewares.Require1FA(handlers.TimeBasedOneTimePasswordPOST))) r.POST("/api/secondfactor/totp", middlewareAPI(middlewares.Require1FA(handlers.TimeBasedOneTimePasswordPOST)))
} }
if !config.Webauthn.Disable { if !config.Webauthn.Disable {
// Webauthn Endpoints. // Webauthn Endpoints.
r.POST("/api/secondfactor/webauthn/identity/start", middleware(middlewares.Require1FA(handlers.WebauthnIdentityStart))) r.POST("/api/secondfactor/webauthn/identity/start", middlewareAPI(middlewares.Require1FA(handlers.WebauthnIdentityStart)))
r.POST("/api/secondfactor/webauthn/identity/finish", middleware(middlewares.Require1FA(handlers.WebauthnIdentityFinish))) r.POST("/api/secondfactor/webauthn/identity/finish", middlewareAPI(middlewares.Require1FA(handlers.WebauthnIdentityFinish)))
r.POST("/api/secondfactor/webauthn/attestation", middleware(middlewares.Require1FA(handlers.WebauthnAttestationPOST))) r.POST("/api/secondfactor/webauthn/attestation", middlewareAPI(middlewares.Require1FA(handlers.WebauthnAttestationPOST)))
r.GET("/api/secondfactor/webauthn/assertion", middleware(middlewares.Require1FA(handlers.WebauthnAssertionGET))) r.GET("/api/secondfactor/webauthn/assertion", middlewareAPI(middlewares.Require1FA(handlers.WebauthnAssertionGET)))
r.POST("/api/secondfactor/webauthn/assertion", middleware(middlewares.Require1FA(handlers.WebauthnAssertionPOST))) r.POST("/api/secondfactor/webauthn/assertion", middlewareAPI(middlewares.Require1FA(handlers.WebauthnAssertionPOST)))
} }
// Configure DUO api endpoint only if configuration exists. // Configure DUO api endpoint only if configuration exists.
@ -198,9 +203,9 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
config.DuoAPI.Hostname, "")) config.DuoAPI.Hostname, ""))
} }
r.GET("/api/secondfactor/duo_devices", middleware(middlewares.Require1FA(handlers.DuoDevicesGET(duoAPI)))) r.GET("/api/secondfactor/duo_devices", middlewareAPI(middlewares.Require1FA(handlers.DuoDevicesGET(duoAPI))))
r.POST("/api/secondfactor/duo", middleware(middlewares.Require1FA(handlers.DuoPOST(duoAPI)))) r.POST("/api/secondfactor/duo", middlewareAPI(middlewares.Require1FA(handlers.DuoPOST(duoAPI))))
r.POST("/api/secondfactor/duo_device", middleware(middlewares.Require1FA(handlers.DuoDevicePOST))) r.POST("/api/secondfactor/duo_device", middlewareAPI(middlewares.Require1FA(handlers.DuoDevicePOST)))
} }
if config.Server.EnablePprof { if config.Server.EnablePprof {
@ -212,23 +217,23 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
} }
if providers.OpenIDConnect.Fosite != nil { if providers.OpenIDConnect.Fosite != nil {
r.GET("/api/oidc/consent", middleware(handlers.OpenIDConnectConsentGET)) r.GET("/api/oidc/consent", middlewareAPI(handlers.OpenIDConnectConsentGET))
r.POST("/api/oidc/consent", middleware(handlers.OpenIDConnectConsentPOST)) r.POST("/api/oidc/consent", middlewareAPI(handlers.OpenIDConnectConsentPOST))
allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins) allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins)
r.OPTIONS(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.HandleOPTIONS) r.OPTIONS(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.HandleOPTIONS)
r.GET(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.Middleware(middleware(handlers.OpenIDConnectConfigurationWellKnownGET))) r.GET(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.Middleware(middlewareAPI(handlers.OpenIDConnectConfigurationWellKnownGET)))
r.OPTIONS(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.HandleOPTIONS) r.OPTIONS(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.HandleOPTIONS)
r.GET(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.Middleware(middleware(handlers.OAuthAuthorizationServerWellKnownGET))) r.GET(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.Middleware(middlewareAPI(handlers.OAuthAuthorizationServerWellKnownGET)))
r.OPTIONS(oidc.JWKsPath, policyCORSPublicGET.HandleOPTIONS) r.OPTIONS(oidc.JWKsPath, policyCORSPublicGET.HandleOPTIONS)
r.GET(oidc.JWKsPath, policyCORSPublicGET.Middleware(middleware(handlers.JSONWebKeySetGET))) r.GET(oidc.JWKsPath, policyCORSPublicGET.Middleware(middlewareAPI(handlers.JSONWebKeySetGET)))
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS) r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS)
r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(middleware(handlers.JSONWebKeySetGET))) r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(middlewareAPI(handlers.JSONWebKeySetGET)))
policyCORSAuthorization := middlewares.NewCORSPolicyBuilder(). policyCORSAuthorization := middlewares.NewCORSPolicyBuilder().
WithAllowedMethods("OPTIONS", "GET"). WithAllowedMethods("OPTIONS", "GET").
@ -237,11 +242,11 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
Build() Build()
r.OPTIONS(oidc.AuthorizationPath, policyCORSAuthorization.HandleOnlyOPTIONS) r.OPTIONS(oidc.AuthorizationPath, policyCORSAuthorization.HandleOnlyOPTIONS)
r.GET(oidc.AuthorizationPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) r.GET(oidc.AuthorizationPath, middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET)))
// TODO (james-d-elliott): Remove in GA. This is a legacy endpoint. // TODO (james-d-elliott): Remove in GA. This is a legacy endpoint.
r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS) r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS)
r.GET("/api/oidc/authorize", middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) r.GET("/api/oidc/authorize", middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET)))
policyCORSToken := middlewares.NewCORSPolicyBuilder(). policyCORSToken := middlewares.NewCORSPolicyBuilder().
WithAllowCredentials(true). WithAllowCredentials(true).
@ -251,7 +256,7 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
Build() Build()
r.OPTIONS(oidc.TokenPath, policyCORSToken.HandleOPTIONS) r.OPTIONS(oidc.TokenPath, policyCORSToken.HandleOPTIONS)
r.POST(oidc.TokenPath, policyCORSToken.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST)))) r.POST(oidc.TokenPath, policyCORSToken.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST))))
policyCORSUserinfo := middlewares.NewCORSPolicyBuilder(). policyCORSUserinfo := middlewares.NewCORSPolicyBuilder().
WithAllowCredentials(true). WithAllowCredentials(true).
@ -261,8 +266,8 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
Build() Build()
r.OPTIONS(oidc.UserinfoPath, policyCORSUserinfo.HandleOPTIONS) r.OPTIONS(oidc.UserinfoPath, policyCORSUserinfo.HandleOPTIONS)
r.GET(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) r.GET(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo))))
r.POST(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) r.POST(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo))))
policyCORSIntrospection := middlewares.NewCORSPolicyBuilder(). policyCORSIntrospection := middlewares.NewCORSPolicyBuilder().
WithAllowCredentials(true). WithAllowCredentials(true).
@ -272,11 +277,11 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
Build() Build()
r.OPTIONS(oidc.IntrospectionPath, policyCORSIntrospection.HandleOPTIONS) r.OPTIONS(oidc.IntrospectionPath, policyCORSIntrospection.HandleOPTIONS)
r.POST(oidc.IntrospectionPath, policyCORSIntrospection.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) r.POST(oidc.IntrospectionPath, policyCORSIntrospection.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST))))
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS) r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS)
r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST))))
policyCORSRevocation := middlewares.NewCORSPolicyBuilder(). policyCORSRevocation := middlewares.NewCORSPolicyBuilder().
WithAllowCredentials(true). WithAllowCredentials(true).
@ -286,11 +291,11 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
Build() Build()
r.OPTIONS(oidc.RevocationPath, policyCORSRevocation.HandleOPTIONS) r.OPTIONS(oidc.RevocationPath, policyCORSRevocation.HandleOPTIONS)
r.POST(oidc.RevocationPath, policyCORSRevocation.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) r.POST(oidc.RevocationPath, policyCORSRevocation.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST))))
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS) r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS)
r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middlewareAPI(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST))))
} }
r.NotFound = handlerNotFound(middleware(serveIndexHandler)) r.NotFound = handlerNotFound(middleware(serveIndexHandler))
@ -298,10 +303,9 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
r.HandleMethodNotAllowed = true r.HandleMethodNotAllowed = true
r.MethodNotAllowed = handlerMethodNotAllowed r.MethodNotAllowed = handlerMethodNotAllowed
handler := middlewares.LogRequest(middlewares.SecurityHeaders(r.Handler))
if config.Server.Path != "" { if config.Server.Path != "" {
handler = middlewares.StripPath(config.Server.Path, handler) return middlewares.StripPath(config.Server.Path)(middlewares.LogRequest(r.Handler))
} }
return handler return middlewares.LogRequest(r.Handler)
} }