Skip to content

Commit

Permalink
Merge branch 'main' into web/bug/fix-wdio-and-lint
Browse files Browse the repository at this point in the history
* main:
  website: update release notes for 2024.8.3 and 2024.6.5 (#11541)
  website/docs: added a Docs banner to announce new docs structure (#11525)
  security: fix CVE-2024-47070 (#11536)
  security: fix CVE-2024-47077 (#11535)
  sources/ldap: fix ms_ad userAccountControl not checking for lockout (#11532)
  web: Fix missing integrity fields in package-lock.json (#11509)
  core, web: update translations (#11527)
  core: bump ruff from 0.6.7 to 0.6.8 (#11528)
  web: bump the wdio group across 2 directories with 3 updates (#11529)
  web: bump @patternfly/elements from 4.0.1 to 4.0.2 in /web (#11530)
  web: bump @types/node from 22.7.2 to 22.7.3 in /web (#11531)
  • Loading branch information
kensternberg-authentik committed Sep 27, 2024
2 parents 705f096 + 384ca87 commit e71e875
Show file tree
Hide file tree
Showing 22 changed files with 3,448 additions and 212 deletions.
16 changes: 16 additions & 0 deletions authentik/lib/tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ def test_forward_for(self):
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2")

def test_forward_for_invalid(self):
"""Test invalid forward for"""
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip)

def test_fake_outpost(self):
"""Test faked IP which is overridden by an outpost"""
token = Token.objects.create(
Expand All @@ -53,6 +58,17 @@ def test_fake_outpost(self):
},
)
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Invalid, not a real IP
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save()
request = self.factory.get(
"/",
**{
ClientIPMiddleware.outpost_remote_ip_header: "foobar",
ClientIPMiddleware.outpost_token_header: token.key,
},
)
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Valid
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save()
Expand Down
36 changes: 35 additions & 1 deletion authentik/providers/oauth2/tests/test_introspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def setUp(self) -> None:
self.app = Application.objects.create(
name=generate_id(), slug=generate_id(), provider=self.provider
)
self.app.save()
self.user = create_test_admin_user()
self.auth = b64encode(
f"{self.provider.client_id}:{self.provider.client_secret}".encode()
Expand Down Expand Up @@ -114,6 +113,41 @@ def test_introspect_invalid_token(self):
},
)

def test_introspect_invalid_provider(self):
"""Test introspection (mismatched provider and token)"""
provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(),
authorization_flow=create_test_flow(),
redirect_uris="",
signing_key=create_test_cert(),
)
auth = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()

token: AccessToken = AccessToken.objects.create(
provider=self.provider,
user=self.user,
token=generate_id(),
auth_time=timezone.now(),
_scope="openid user profile",
_id_token=json.dumps(
asdict(
IDToken("foo", "bar"),
)
),
)
res = self.client.post(
reverse("authentik_providers_oauth2:token-introspection"),
HTTP_AUTHORIZATION=f"Basic {auth}",
data={"token": token.token},
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content.decode(),
{
"active": False,
},
)

def test_introspect_invalid_auth(self):
"""Test introspect (invalid auth)"""
res = self.client.post(
Expand Down
4 changes: 2 additions & 2 deletions authentik/providers/oauth2/views/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ def from_request(request: HttpRequest) -> "TokenIntrospectionParams":
if not provider:
raise TokenIntrospectionError

access_token = AccessToken.objects.filter(token=raw_token).first()
access_token = AccessToken.objects.filter(token=raw_token, provider=provider).first()
if access_token:
return TokenIntrospectionParams(access_token, provider)
refresh_token = RefreshToken.objects.filter(token=raw_token).first()
refresh_token = RefreshToken.objects.filter(token=raw_token, provider=provider).first()
if refresh_token:
return TokenIntrospectionParams(refresh_token, provider)
LOGGER.debug("Token does not exist", token=raw_token)
Expand Down
23 changes: 17 additions & 6 deletions authentik/root/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from collections.abc import Callable
from hashlib import sha512
from ipaddress import ip_address
from time import perf_counter, time
from typing import Any

Expand Down Expand Up @@ -174,6 +175,7 @@ class ClientIPMiddleware:

def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
self.get_response = get_response
self.logger = get_logger().bind()

def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers.
Expand All @@ -185,11 +187,16 @@ def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str:
"HTTP_X_FORWARDED_FOR",
"REMOTE_ADDR",
)
for _header in headers:
if _header in meta:
ips: list[str] = meta.get(_header).split(",")
return ips[0].strip()
return self.default_ip
try:
for _header in headers:
if _header in meta:
ips: list[str] = meta.get(_header).split(",")
# Ensure the IP parses as a valid IP
return str(ip_address(ips[0].strip()))
return self.default_ip
except ValueError as exc:
self.logger.debug("Invalid remote IP", exc=exc)
return self.default_ip

# FIXME: this should probably not be in `root` but rather in a middleware in `outposts`
# but for now it's fine
Expand Down Expand Up @@ -226,7 +233,11 @@ def _get_outpost_override_ip(self, request: HttpRequest) -> str | None:
Scope.get_isolation_scope().set_user(sentry_user)
# Set the outpost service account on the request
setattr(request, self.request_attr_outpost_user, user)
return delegated_ip
try:
return str(ip_address(delegated_ip))
except ValueError as exc:
self.logger.debug("Invalid remote IP from Outpost", exc=exc)
return None

def _get_client_ip(self, request: HttpRequest | None) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers.
Expand Down
4 changes: 3 additions & 1 deletion authentik/sources/ldap/sync/vendor/ms_ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ def ms_check_uac(self, attributes: dict[str, Any], user: User):
# /useraccountcontrol-manipulate-account-properties
uac_bit = attributes.get("userAccountControl", 512)
uac = UserAccountControl(uac_bit)
is_active = UserAccountControl.ACCOUNTDISABLE not in uac
is_active = (
UserAccountControl.ACCOUNTDISABLE not in uac and UserAccountControl.LOCKOUT not in uac
)
if is_active != user.is_active:
user.is_active = is_active
user.save()
2 changes: 2 additions & 0 deletions blueprints/default/flow-default-authentication-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,5 @@ entries:
order: 10
target: !KeyOf default-authentication-flow-password-binding
policy: !KeyOf default-authentication-flow-password-optional
attrs:
failure_result: true
38 changes: 19 additions & 19 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 34 additions & 34 deletions tests/wdio/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e71e875

Please sign in to comment.