fix(server): missing cache and xss headers (#3289)
Addresses documentation and a couple of headers which were missed.pull/3294/head
parent
cac8919f97
commit
0855ea2f71
|
@ -90,9 +90,14 @@ 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
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,12 @@ var (
|
||||||
|
|
||||||
headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions)
|
headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions)
|
||||||
headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy)
|
headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy)
|
||||||
|
headerXFrameOptions = []byte(fasthttp.HeaderXFrameOptions)
|
||||||
|
headerPragma = []byte(fasthttp.HeaderPragma)
|
||||||
|
headerCacheControl = []byte(fasthttp.HeaderCacheControl)
|
||||||
|
headerXXSSProtection = []byte(fasthttp.HeaderXXSSProtection)
|
||||||
|
headerContentSecurityPolicy = []byte(fasthttp.HeaderContentSecurityPolicy)
|
||||||
|
|
||||||
headerPermissionsPolicy = []byte("Permissions-Policy")
|
headerPermissionsPolicy = []byte("Permissions-Policy")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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=()")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ 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(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
uri := ctx.RequestURI()
|
uri := ctx.RequestURI()
|
||||||
|
|
||||||
|
@ -20,4 +21,5 @@ func StripPath(path string, next fasthttp.RequestHandler) fasthttp.RequestHandle
|
||||||
|
|
||||||
next(ctx)
|
next(ctx)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue