Compare commits
2 Commits
version/20
...
version/20
Author | SHA1 | Date | |
---|---|---|---|
2a3d2cd262 | |||
d9aab79c62 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 2023.8.5
|
current_version = 2023.8.6
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
from os import environ
|
from os import environ
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
__version__ = "2023.8.5"
|
__version__ = "2023.8.6"
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,6 +85,25 @@ class TestAuthorize(OAuthTestCase):
|
|||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
|
||||||
|
def test_blocked_redirect_uri(self):
|
||||||
|
"""test missing/invalid redirect URI"""
|
||||||
|
OAuth2Provider.objects.create(
|
||||||
|
name=generate_id(),
|
||||||
|
client_id="test",
|
||||||
|
authorization_flow=create_test_flow(),
|
||||||
|
redirect_uris="data:local.invalid",
|
||||||
|
)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get(
|
||||||
|
"/",
|
||||||
|
data={
|
||||||
|
"response_type": "code",
|
||||||
|
"client_id": "test",
|
||||||
|
"redirect_uri": "data:localhost",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
|
||||||
def test_invalid_redirect_uri_empty(self):
|
def test_invalid_redirect_uri_empty(self):
|
||||||
"""test missing/invalid redirect URI"""
|
"""test missing/invalid redirect URI"""
|
||||||
provider = OAuth2Provider.objects.create(
|
provider = OAuth2Provider.objects.create(
|
||||||
|
@ -74,6 +74,7 @@ PLAN_CONTEXT_PARAMS = "goauthentik.io/providers/oauth2/params"
|
|||||||
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
||||||
|
|
||||||
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
||||||
|
FORBIDDEN_URI_SCHEMES = {"javascript", "data", "vbscript"}
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
@ -174,6 +175,10 @@ class OAuthAuthorizationParams:
|
|||||||
self.check_scope()
|
self.check_scope()
|
||||||
self.check_nonce()
|
self.check_nonce()
|
||||||
self.check_code_challenge()
|
self.check_code_challenge()
|
||||||
|
if self.request:
|
||||||
|
raise AuthorizeError(
|
||||||
|
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||||
|
)
|
||||||
|
|
||||||
def check_redirect_uri(self):
|
def check_redirect_uri(self):
|
||||||
"""Redirect URI validation."""
|
"""Redirect URI validation."""
|
||||||
@ -211,10 +216,9 @@ class OAuthAuthorizationParams:
|
|||||||
expected=allowed_redirect_urls,
|
expected=allowed_redirect_urls,
|
||||||
)
|
)
|
||||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
if self.request:
|
# Check against forbidden schemes
|
||||||
raise AuthorizeError(
|
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
)
|
|
||||||
|
|
||||||
def check_scope(self):
|
def check_scope(self):
|
||||||
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
||||||
|
@ -6,6 +6,7 @@ from hashlib import sha256
|
|||||||
from re import error as RegexError
|
from re import error as RegexError
|
||||||
from re import fullmatch
|
from re import fullmatch
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@ -53,6 +54,7 @@ from authentik.providers.oauth2.models import (
|
|||||||
RefreshToken,
|
RefreshToken,
|
||||||
)
|
)
|
||||||
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
|
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
|
||||||
|
from authentik.providers.oauth2.views.authorize import FORBIDDEN_URI_SCHEMES
|
||||||
from authentik.sources.oauth.models import OAuthSource
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
||||||
|
|
||||||
@ -204,6 +206,10 @@ class TokenParams:
|
|||||||
).from_http(request)
|
).from_http(request)
|
||||||
raise TokenError("invalid_client")
|
raise TokenError("invalid_client")
|
||||||
|
|
||||||
|
# Check against forbidden schemes
|
||||||
|
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||||
|
raise TokenError("invalid_request")
|
||||||
|
|
||||||
self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
|
self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
|
||||||
if not self.authorization_code:
|
if not self.authorization_code:
|
||||||
LOGGER.warning("Code does not exist", code=raw_code)
|
LOGGER.warning("Code does not exist", code=raw_code)
|
||||||
|
@ -32,7 +32,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
server:
|
server:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.5}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.6}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@ -53,7 +53,7 @@ services:
|
|||||||
- postgresql
|
- postgresql
|
||||||
- redis
|
- redis
|
||||||
worker:
|
worker:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.5}
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.6}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
|||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2023.8.5"
|
const VERSION = "2023.8.6"
|
||||||
|
@ -113,7 +113,7 @@ filterwarnings = [
|
|||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "authentik"
|
name = "authentik"
|
||||||
version = "2023.8.5"
|
version = "2023.8.6"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: authentik
|
title: authentik
|
||||||
version: 2023.8.5
|
version: 2023.8.6
|
||||||
description: Making authentication simple.
|
description: Making authentication simple.
|
||||||
contact:
|
contact:
|
||||||
email: hello@goauthentik.io
|
email: hello@goauthentik.io
|
||||||
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
|||||||
export const ERROR_CLASS = "pf-m-danger";
|
export const ERROR_CLASS = "pf-m-danger";
|
||||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||||
export const CURRENT_CLASS = "pf-m-current";
|
export const CURRENT_CLASS = "pf-m-current";
|
||||||
export const VERSION = "2023.8.5";
|
export const VERSION = "2023.8.6";
|
||||||
export const TITLE_DEFAULT = "authentik";
|
export const TITLE_DEFAULT = "authentik";
|
||||||
export const ROUTE_SEPARATOR = ";";
|
export const ROUTE_SEPARATOR = ";";
|
||||||
|
|
||||||
|
@ -159,6 +159,14 @@ image:
|
|||||||
|
|
||||||
- \*: fix [GHSA-rjvp-29xq-f62w](../security/GHSA-rjvp-29xq-f62w), Reported by [@devSparkle](https://github.com/devSparkle)
|
- \*: fix [GHSA-rjvp-29xq-f62w](../security/GHSA-rjvp-29xq-f62w), Reported by [@devSparkle](https://github.com/devSparkle)
|
||||||
|
|
||||||
|
## Fixed in 2023.8.5
|
||||||
|
|
||||||
|
- security: fix [CVE-2023-48228](../../security/CVE-2023-48228.md), Reported by [@Sapd](https://github.com/Sapd) (#7666)
|
||||||
|
|
||||||
|
## Fixed in 2023.8.6
|
||||||
|
|
||||||
|
- providers/oauth2: fix [CVE-2024-21637](../../security/CVE-2024-21637.md), Reported by [@lauritzh](https://github.com/lauritzh) (#8104)
|
||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
39
website/docs/security/CVE-2024-21637.md
Normal file
39
website/docs/security/CVE-2024-21637.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# CVE-2024-21637
|
||||||
|
|
||||||
|
_Reported by [@lauritzh](https://github.com/lauritzh)_
|
||||||
|
|
||||||
|
## XSS in Authentik via JavaScript-URI as Redirect URI and form_post Response Mode
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Given an OAuth2 provider configured with allowed redirect URIs set to `*` or `.*`, an attacker can send an OAuth Authorization request using `response_mode=form_post` and setting `redirect_uri` to a malicious URI, to capture authentik's session token.
|
||||||
|
|
||||||
|
### Patches
|
||||||
|
|
||||||
|
authentik 2023.8.6 and 2023.10.6 fix this issue.
|
||||||
|
|
||||||
|
### Impact
|
||||||
|
|
||||||
|
The impact depends on the attack scenario. In the following I will describe the two scenario that were identified for Authentik.
|
||||||
|
|
||||||
|
#### Redirect URI Misconfiguration
|
||||||
|
|
||||||
|
While advising that this may cause security issues, Authentik generally allows wildcards as Redirect URI. Therefore, using a wildcard-only effectively allowing arbitrary URLS is possible misconfiguration that may be present in real-world instances.
|
||||||
|
|
||||||
|
In such cases, unauthenticated and unprivileged attackers can perform the above described actions.
|
||||||
|
|
||||||
|
### User with (only) App Administration Permissions
|
||||||
|
|
||||||
|
A more likely scenario is an administrative user (e.g. a normal developer) having only permissions to manage applications.
|
||||||
|
|
||||||
|
This relatively user could use the described attacks to perform a privilege escalation.
|
||||||
|
|
||||||
|
### Workaround
|
||||||
|
|
||||||
|
It is recommended to upgrade to the patched version of authentik. If not possible, ensure that OAuth2 providers do not use a wildcard (`*` or `.*`) value as allowed redirect URI setting. (This is _not_ exploitable if part of the redirect URI has a wildcard, for example `https://foo-.*\.bar\.com`)
|
||||||
|
|
||||||
|
### For more information
|
||||||
|
|
||||||
|
If you have any questions or comments about this advisory:
|
||||||
|
|
||||||
|
- Email us at [security@goauthentik.io](mailto:security@goauthentik.io)
|
@ -362,6 +362,7 @@ const docsSidebar = {
|
|||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
"security/policy",
|
"security/policy",
|
||||||
|
"security/CVE-2024-21637",
|
||||||
"security/CVE-2023-48228",
|
"security/CVE-2023-48228",
|
||||||
"security/GHSA-rjvp-29xq-f62w",
|
"security/GHSA-rjvp-29xq-f62w",
|
||||||
"security/CVE-2023-39522",
|
"security/CVE-2023-39522",
|
||||||
|
Reference in New Issue
Block a user