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:
Jens L 2023-01-17 18:56:48 +01:00 committed by GitHub
parent c73fce4f58
commit 23c69c456a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 9 deletions

View file

@ -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",

View file

@ -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.",
),
),
]

View file

@ -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"),

View file

@ -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 {

View file

@ -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 "

View file

@ -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:

View file

@ -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

View file

@ -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