core: fix PropertyMapping's globals not matching Expression policy

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-06-21 15:54:43 +02:00
parent 70ccc63702
commit 831b32c279
5 changed files with 31 additions and 22 deletions

View File

@ -3,23 +3,33 @@ from traceback import format_tb
from typing import Optional from typing import Optional
from django.http import HttpRequest from django.http import HttpRequest
from guardian.utils import get_anonymous_user
from authentik.core.models import User from authentik.core.models import PropertyMapping, User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.lib.expression.evaluator import BaseEvaluator from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.policies.types import PolicyRequest
class PropertyMappingEvaluator(BaseEvaluator): class PropertyMappingEvaluator(BaseEvaluator):
"""Custom Evalautor that adds some different context variables.""" """Custom Evalautor that adds some different context variables."""
def set_context( def set_context(
self, user: Optional[User], request: Optional[HttpRequest], **kwargs self,
user: Optional[User],
request: Optional[HttpRequest],
mapping: PropertyMapping,
**kwargs,
): ):
"""Update context with context from PropertyMapping's evaluate""" """Update context with context from PropertyMapping's evaluate"""
req = PolicyRequest(user=get_anonymous_user())
req.obj = mapping
if user: if user:
req.user = user
self._context["user"] = user self._context["user"] = user
if request: if request:
self._context["request"] = request req.http_request = request
self._context["request"] = req
self._context.update(**kwargs) self._context.update(**kwargs)
def handle_error(self, exc: Exception, expression_source: str): def handle_error(self, exc: Exception, expression_source: str):
@ -30,9 +40,8 @@ class PropertyMappingEvaluator(BaseEvaluator):
expression=expression_source, expression=expression_source,
message=error_string, message=error_string,
) )
if "user" in self._context:
event.set_user(self._context["user"])
if "request" in self._context: if "request" in self._context:
event.from_http(self._context["request"]) req: PolicyRequest = self._context["request"]
event.from_http(req.http_request, req.user)
return return
event.save() event.save()

View File

@ -461,7 +461,7 @@ class PropertyMapping(SerializerModel, ManagedModel):
from authentik.core.expression import PropertyMappingEvaluator from authentik.core.expression import PropertyMappingEvaluator
evaluator = PropertyMappingEvaluator() evaluator = PropertyMappingEvaluator()
evaluator.set_context(user, request, **kwargs) evaluator.set_context(user, request, self, **kwargs)
try: try:
return evaluator.evaluate(self.expression) return evaluator.evaluate(self.expression)
except (ValueError, SyntaxError) as exc: except (ValueError, SyntaxError) as exc:

View File

@ -9,7 +9,7 @@ return {}
""" """
SCOPE_EMAIL_EXPRESSION = """ SCOPE_EMAIL_EXPRESSION = """
return { return {
"email": user.email, "email": request.user.email,
"email_verified": True "email_verified": True
} }
""" """
@ -17,14 +17,14 @@ SCOPE_PROFILE_EXPRESSION = """
return { return {
# Because authentik only saves the user's full name, and has no concept of first and last names, # Because authentik only saves the user's full name, and has no concept of first and last names,
# the full name is used as given name. # the full name is used as given name.
# You can override this behaviour in custom mappings, i.e. `user.name.split(" ")` # You can override this behaviour in custom mappings, i.e. `request.user.name.split(" ")`
"name": user.name, "name": request.user.name,
"given_name": user.name, "given_name": request.user.name,
"family_name": "", "family_name": "",
"preferred_username": user.username, "preferred_username": request.user.username,
"nickname": user.username, "nickname": request.user.username,
# groups is not part of the official userinfo schema, but is a quasi-standard # groups is not part of the official userinfo schema, but is a quasi-standard
"groups": [group.name for group in user.ak_groups.all()], "groups": [group.name for group in request.user.ak_groups.all()],
} }
""" """

View File

@ -8,7 +8,7 @@ SCOPE_AK_PROXY_EXPRESSION = """
# which are used for example for the HTTP-Basic Authentication mapping. # which are used for example for the HTTP-Basic Authentication mapping.
return { return {
"ak_proxy": { "ak_proxy": {
"user_attributes": user.group_attributes() "user_attributes": request.user.group_attributes()
} }
}""" }"""

View File

@ -3,7 +3,7 @@ from authentik.managed.manager import EnsureExists, ObjectManager
from authentik.providers.saml.models import SAMLPropertyMapping from authentik.providers.saml.models import SAMLPropertyMapping
GROUP_EXPRESSION = """ GROUP_EXPRESSION = """
for group in user.ak_groups.all(): for group in request.user.ak_groups.all():
yield group.name yield group.name
""" """
@ -18,7 +18,7 @@ class SAMLProviderManager(ObjectManager):
"goauthentik.io/providers/saml/upn", "goauthentik.io/providers/saml/upn",
name="authentik default SAML Mapping: UPN", name="authentik default SAML Mapping: UPN",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
expression="return user.attributes.get('upn', user.email)", expression="return request.user.attributes.get('upn', request.user.email)",
friendly_name="", friendly_name="",
), ),
EnsureExists( EnsureExists(
@ -26,7 +26,7 @@ class SAMLProviderManager(ObjectManager):
"goauthentik.io/providers/saml/name", "goauthentik.io/providers/saml/name",
name="authentik default SAML Mapping: Name", name="authentik default SAML Mapping: Name",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
expression="return user.name", expression="return request.user.name",
friendly_name="", friendly_name="",
), ),
EnsureExists( EnsureExists(
@ -34,7 +34,7 @@ class SAMLProviderManager(ObjectManager):
"goauthentik.io/providers/saml/email", "goauthentik.io/providers/saml/email",
name="authentik default SAML Mapping: Email", name="authentik default SAML Mapping: Email",
saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", saml_name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
expression="return user.email", expression="return request.user.email",
friendly_name="", friendly_name="",
), ),
EnsureExists( EnsureExists(
@ -42,7 +42,7 @@ class SAMLProviderManager(ObjectManager):
"goauthentik.io/providers/saml/username", "goauthentik.io/providers/saml/username",
name="authentik default SAML Mapping: Username", name="authentik default SAML Mapping: Username",
saml_name="http://schemas.goauthentik.io/2021/02/saml/username", saml_name="http://schemas.goauthentik.io/2021/02/saml/username",
expression="return user.username", expression="return request.user.username",
friendly_name="", friendly_name="",
), ),
EnsureExists( EnsureExists(
@ -50,7 +50,7 @@ class SAMLProviderManager(ObjectManager):
"goauthentik.io/providers/saml/uid", "goauthentik.io/providers/saml/uid",
name="authentik default SAML Mapping: User ID", name="authentik default SAML Mapping: User ID",
saml_name="http://schemas.goauthentik.io/2021/02/saml/uid", saml_name="http://schemas.goauthentik.io/2021/02/saml/uid",
expression="return user.pk", expression="return request.user.pk",
friendly_name="", friendly_name="",
), ),
EnsureExists( EnsureExists(
@ -68,7 +68,7 @@ class SAMLProviderManager(ObjectManager):
saml_name=( saml_name=(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"
), ),
expression="return user.username", expression="return request.user.username",
friendly_name="", friendly_name="",
), ),
] ]