providers/proxy: add setting to intercept authorization header (#4457)
* add setting to intercept authorization header Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename to intercept_header_auth Signed-off-by: Jens Langhammer <jens@goauthentik.io> Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
c73fce4f58
commit
23c69c456a
|
@ -88,6 +88,7 @@ class ProxyProviderSerializer(ProviderSerializer):
|
||||||
"basic_auth_password_attribute",
|
"basic_auth_password_attribute",
|
||||||
"basic_auth_user_attribute",
|
"basic_auth_user_attribute",
|
||||||
"mode",
|
"mode",
|
||||||
|
"intercept_header_auth",
|
||||||
"redirect_uris",
|
"redirect_uris",
|
||||||
"cookie_domain",
|
"cookie_domain",
|
||||||
"jwks_sources",
|
"jwks_sources",
|
||||||
|
@ -171,6 +172,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
|
||||||
"mode",
|
"mode",
|
||||||
"cookie_domain",
|
"cookie_domain",
|
||||||
"token_validity",
|
"token_validity",
|
||||||
|
"intercept_header_auth",
|
||||||
"scopes_to_request",
|
"scopes_to_request",
|
||||||
"assigned_application_slug",
|
"assigned_application_slug",
|
||||||
"assigned_application_name",
|
"assigned_application_name",
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 4.1.5 on 2023-01-17 10:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_providers_proxy", "0001_squashed_0014_proxy_v2"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="proxyprovider",
|
||||||
|
name="intercept_header_auth",
|
||||||
|
field=models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text="When enabled, this provider will intercept the authorization header and authenticate requests based on its value.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -74,6 +74,13 @@ class ProxyProvider(OutpostModel, OAuth2Provider):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
intercept_header_auth = models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text=_(
|
||||||
|
"When enabled, this provider will intercept the authorization header and authenticate "
|
||||||
|
"requests based on its value."
|
||||||
|
),
|
||||||
|
)
|
||||||
basic_auth_enabled = models.BooleanField(
|
basic_auth_enabled = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
verbose_name=_("Set HTTP-Basic Authentication"),
|
verbose_name=_("Set HTTP-Basic Authentication"),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package application
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -35,12 +34,11 @@ func (a *Application) redirectToStart(rw http.ResponseWriter, r *http.Request) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.WithError(err).Warning("failed to decode session")
|
a.log.WithError(err).Warning("failed to decode session")
|
||||||
}
|
}
|
||||||
if r.Header.Get(constants.HeaderNoRedirect) != "" ||
|
if r.Header.Get(constants.HeaderAuthorization) != "" && *a.proxyConfig.InterceptHeaderAuth {
|
||||||
r.URL.Query().Get(strings.ToLower(constants.HeaderNoRedirect)) != "" {
|
|
||||||
rw.WriteHeader(401)
|
rw.WriteHeader(401)
|
||||||
er := a.errorTemplates.Execute(rw, ErrorPageData{
|
er := a.errorTemplates.Execute(rw, ErrorPageData{
|
||||||
Title: "Unauthenticated",
|
Title: "Unauthenticated",
|
||||||
Message: fmt.Sprintf("Due to '%s' being set, no redirect is performed.", constants.HeaderNoRedirect),
|
Message: "Due to 'Receive header authentication' being set, no redirect is performed.",
|
||||||
ProxyPrefix: "/outpost.goauthentik.io",
|
ProxyPrefix: "/outpost.goauthentik.io",
|
||||||
})
|
})
|
||||||
if er != nil {
|
if er != nil {
|
||||||
|
|
|
@ -8,6 +8,5 @@ const SessionClaims = "claims"
|
||||||
const SessionRedirect = "redirect"
|
const SessionRedirect = "redirect"
|
||||||
|
|
||||||
const HeaderAuthorization = "Authorization"
|
const HeaderAuthorization = "Authorization"
|
||||||
const HeaderNoRedirect = "X-Authentik-No-Redirect"
|
|
||||||
|
|
||||||
const AuthBearer = "Bearer "
|
const AuthBearer = "Bearer "
|
||||||
|
|
16
schema.yml
16
schema.yml
|
@ -34363,6 +34363,10 @@ components:
|
||||||
- $ref: '#/components/schemas/ProxyMode'
|
- $ref: '#/components/schemas/ProxyMode'
|
||||||
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
||||||
Exclusive with internal_host.
|
Exclusive with internal_host.
|
||||||
|
intercept_header_auth:
|
||||||
|
type: boolean
|
||||||
|
description: When enabled, this provider will intercept the authorization
|
||||||
|
header and authenticate requests based on its value.
|
||||||
cookie_domain:
|
cookie_domain:
|
||||||
type: string
|
type: string
|
||||||
jwks_sources:
|
jwks_sources:
|
||||||
|
@ -35681,6 +35685,10 @@ components:
|
||||||
format: double
|
format: double
|
||||||
nullable: true
|
nullable: true
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
intercept_header_auth:
|
||||||
|
type: boolean
|
||||||
|
description: When enabled, this provider will intercept the authorization
|
||||||
|
header and authenticate requests based on its value.
|
||||||
scopes_to_request:
|
scopes_to_request:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -35782,6 +35790,10 @@ components:
|
||||||
- $ref: '#/components/schemas/ProxyMode'
|
- $ref: '#/components/schemas/ProxyMode'
|
||||||
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
||||||
Exclusive with internal_host.
|
Exclusive with internal_host.
|
||||||
|
intercept_header_auth:
|
||||||
|
type: boolean
|
||||||
|
description: When enabled, this provider will intercept the authorization
|
||||||
|
header and authenticate requests based on its value.
|
||||||
redirect_uris:
|
redirect_uris:
|
||||||
type: string
|
type: string
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
@ -35872,6 +35884,10 @@ components:
|
||||||
- $ref: '#/components/schemas/ProxyMode'
|
- $ref: '#/components/schemas/ProxyMode'
|
||||||
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
description: Enable support for forwardAuth in traefik and nginx auth_request.
|
||||||
Exclusive with internal_host.
|
Exclusive with internal_host.
|
||||||
|
intercept_header_auth:
|
||||||
|
type: boolean
|
||||||
|
description: When enabled, this provider will intercept the authorization
|
||||||
|
header and authenticate requests based on its value.
|
||||||
cookie_domain:
|
cookie_domain:
|
||||||
type: string
|
type: string
|
||||||
jwks_sources:
|
jwks_sources:
|
||||||
|
|
|
@ -449,6 +449,26 @@ ${this.instance?.skipPathRegex}</textarea
|
||||||
<ak-form-group>
|
<ak-form-group>
|
||||||
<span slot="header">${t`Authentication settings`}</span>
|
<span slot="header">${t`Authentication settings`}</span>
|
||||||
<div slot="body" class="pf-c-form">
|
<div slot="body" class="pf-c-form">
|
||||||
|
<ak-form-element-horizontal name="interceptHeaderAuth">
|
||||||
|
<label class="pf-c-switch">
|
||||||
|
<input
|
||||||
|
class="pf-c-switch__input"
|
||||||
|
type="checkbox"
|
||||||
|
?checked=${first(this.instance?.interceptHeaderAuth, true)}
|
||||||
|
/>
|
||||||
|
<span class="pf-c-switch__toggle">
|
||||||
|
<span class="pf-c-switch__toggle-icon">
|
||||||
|
<i class="fas fa-check" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="pf-c-switch__label"
|
||||||
|
>${t`Intercept header authentication`}</span
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`When enabled, authentik will intercept the Authorization header to authenticate the request.`}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal name="basicAuthEnabled">
|
<ak-form-element-horizontal name="basicAuthEnabled">
|
||||||
<label class="pf-c-switch">
|
<label class="pf-c-switch">
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -21,11 +21,9 @@ If the user does not have a matching attribute, authentik falls back to using th
|
||||||
|
|
||||||
## Receiving authentication
|
## Receiving authentication
|
||||||
|
|
||||||
By default, when the proxy provider receives credentials that aren't valid for itself, it will start a normal authentication flow, and redirect to the flow start page. Some applications might require a 401 response to prompt for credentials.
|
By default, when _Intercept header authentication_ is enabled, authentik will intercept the authorization header. If the authorization header value is invalid, an error response will be shown with a 401 status code. Requests without an authorization header will still be redirected to the standard login flow.
|
||||||
|
|
||||||
To always return a 401 response when authentication headers are missing/invalid, you can either set the `X-Authentik-No-Redirect` header to any value or the query parameter `x-authentik-no-redirect` to any value.
|
If the proxied application requires usage of the "Authorization" header, the setting should be disabled. When this setting is disabled, authentik will still attempt to interpret the "Authorization" header, and fall back to the default behaviour if it can't.
|
||||||
|
|
||||||
This is the default behaviour as some applications use the Authorization header for themselves, and as such if the proxy provider would check it, these applications would be inaccessible.
|
|
||||||
|
|
||||||
### Receiving HTTP Basic authentication
|
### Receiving HTTP Basic authentication
|
||||||
|
|
||||||
|
|
Reference in a new issue