diff --git a/Pipfile b/Pipfile index 876f669ae..0cf076c36 100644 --- a/Pipfile +++ b/Pipfile @@ -46,6 +46,7 @@ webauthn = "*" xmlsec = "*" duo-client = "*" ua-parser = "*" +deepmerge = "*" [requires] python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock index 34664222b..4b7f4447d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "4fa1ad681762c867a95410074f31ac5d00119e187e0f38982cd59fdf301cccf5" + "sha256": "f90d9fb4713eaf9c5ffe6a3858e64843670f79ab5007e7debf914c1f094c8d63" }, "pipfile-spec": 6, "requires": { @@ -324,6 +324,14 @@ "markers": "python_version >= '3.6'", "version": "==3.0.2" }, + "deepmerge": { + "hashes": [ + "sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c", + "sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd" + ], + "index": "pypi", + "version": "==0.3.0" + }, "defusedxml": { "hashes": [ "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", @@ -1557,7 +1565,7 @@ "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6", "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d" ], - "markers": "python_version >= '3.6' and python_version < '4'", + "markers": "python_version >= '3.6' and python_version < '4.0'", "version": "==5.8.0" }, "lazy-object-proxy": { diff --git a/authentik/core/models.py b/authentik/core/models.py index fc88d10e8..7e1c377d4 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -6,6 +6,7 @@ from urllib.parse import urlencode from uuid import uuid4 import django.db.models.options as options +from deepmerge import always_merger from django.conf import settings from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import UserManager as DjangoUserManager @@ -114,8 +115,8 @@ class User(GuardianUserMixin, AbstractUser): including the users attributes""" final_attributes = {} for group in self.ak_groups.all().order_by("name"): - final_attributes.update(group.attributes) - final_attributes.update(self.attributes) + always_merger.merge(final_attributes, group.attributes) + always_merger.merge(final_attributes, self.attributes) return final_attributes @cached_property diff --git a/authentik/flows/views.py b/authentik/flows/views.py index 2cfcfc06b..499338d97 100644 --- a/authentik/flows/views.py +++ b/authentik/flows/views.py @@ -365,8 +365,11 @@ class FlowErrorResponse(TemplateResponse): context = {} context["error"] = self.error if self._request.user and self._request.user.is_authenticated: - if self._request.user.is_superuser or self._request.user.attributes.get( - USER_ATTRIBUTE_DEBUG, False + if ( + self._request.user.is_superuser + or self._request.user.group_attributes().get( + USER_ATTRIBUTE_DEBUG, False + ) ): context["tb"] = "".join(format_tb(self.error.__traceback__)) return context diff --git a/authentik/lib/utils/http.py b/authentik/lib/utils/http.py index dc4c003b4..ac4ed67af 100644 --- a/authentik/lib/utils/http.py +++ b/authentik/lib/utils/http.py @@ -33,7 +33,7 @@ def _get_outpost_override_ip(request: HttpRequest) -> Optional[str]: return None if OUTPOST_REMOTE_IP_HEADER not in request.META: return None - if request.user.attributes.get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False): + if request.user.group_attributes().get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False): return None return request.META[OUTPOST_REMOTE_IP_HEADER] diff --git a/authentik/policies/denied.py b/authentik/policies/denied.py index 5da2a30ce..9ffc2a7b1 100644 --- a/authentik/policies/denied.py +++ b/authentik/policies/denied.py @@ -37,7 +37,9 @@ class AccessDeniedResponse(TemplateResponse): if self._request.user and self._request.user.is_authenticated: if ( self._request.user.is_superuser - or self._request.user.attributes.get(USER_ATTRIBUTE_DEBUG, False) + or self._request.user.group_attributes().get( + USER_ATTRIBUTE_DEBUG, False + ) ): context["policy_result"] = self.policy_result return context diff --git a/website/docs/troubleshooting/access.md b/website/docs/troubleshooting/access.md index 294ef6d01..60edbf6f8 100644 --- a/website/docs/troubleshooting/access.md +++ b/website/docs/troubleshooting/access.md @@ -4,7 +4,7 @@ title: Troubleshooting access problems ### I get an access denied error when trying to access an application. -If your user is a superuser, or has the attribute `goauthentik.io/user/debug` set to true: +If your user is a superuser, or has the attribute `goauthentik.io/user/debug` set to true (can also be set on a group level): ![](./authentik_user_debug.png)