wip
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
parent
afc968437d
commit
18d7395e7e
|
@ -95,6 +95,9 @@ outposts:
|
|||
discover: true
|
||||
disable_embedded_outpost: false
|
||||
|
||||
expressions:
|
||||
restricted: false
|
||||
|
||||
ldap:
|
||||
task_timeout_hours: 2
|
||||
page_size: 50
|
||||
|
|
|
@ -6,15 +6,18 @@ from textwrap import indent
|
|||
from typing import Any, Iterable, Optional
|
||||
|
||||
from cachetools import TLRUCache, cached
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import FieldError
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
from rest_framework.serializers import ValidationError
|
||||
from RestrictedPython import compile_restricted, limited_builtins, safe_builtins, utility_builtins
|
||||
from sentry_sdk.hub import Hub
|
||||
from sentry_sdk.tracing import Span
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.policies.models import Policy, PolicyBinding
|
||||
from authentik.policies.process import PolicyProcess
|
||||
|
@ -55,6 +58,10 @@ class BaseEvaluator:
|
|||
"resolve_dns": BaseEvaluator.expr_resolve_dns,
|
||||
"reverse_dns": BaseEvaluator.expr_reverse_dns,
|
||||
}
|
||||
for app in apps.get_app_configs():
|
||||
# Load models from each app
|
||||
for model in app.get_models():
|
||||
self._globals[model.__name__] = model
|
||||
self._context = {}
|
||||
|
||||
@cached(cache=TLRUCache(maxsize=32, ttu=lambda key, value, now: now + 180))
|
||||
|
@ -180,6 +187,18 @@ class BaseEvaluator:
|
|||
full_expression += f"\nresult = handler({handler_signature})"
|
||||
return full_expression
|
||||
|
||||
def compile(self, expression: str) -> Any:
|
||||
"""Parse expression. Raises SyntaxError or ValueError if the syntax is incorrect."""
|
||||
param_keys = self._context.keys()
|
||||
compiler = (
|
||||
compile_restricted if CONFIG.get_bool("epxressions.restricted", False) else compile
|
||||
)
|
||||
return compiler(
|
||||
self.wrap_expression(expression, param_keys),
|
||||
self._filename,
|
||||
"exec",
|
||||
)
|
||||
|
||||
def evaluate(self, expression_source: str) -> Any:
|
||||
"""Parse and evaluate expression. If the syntax is incorrect, a SyntaxError is raised.
|
||||
If any exception is raised during execution, it is raised.
|
||||
|
@ -188,17 +207,18 @@ class BaseEvaluator:
|
|||
span: Span
|
||||
span.description = self._filename
|
||||
span.set_data("expression", expression_source)
|
||||
param_keys = self._context.keys()
|
||||
try:
|
||||
ast_obj = compile(
|
||||
self.wrap_expression(expression_source, param_keys),
|
||||
self._filename,
|
||||
"exec",
|
||||
)
|
||||
ast_obj = self.compile(expression_source)
|
||||
except (SyntaxError, ValueError) as exc:
|
||||
self.handle_error(exc, expression_source)
|
||||
raise exc
|
||||
try:
|
||||
if CONFIG.get_bool("expressions.restricted", False):
|
||||
self._globals["__builtins__"] = {
|
||||
**safe_builtins,
|
||||
**limited_builtins,
|
||||
**utility_builtins,
|
||||
}
|
||||
_locals = self._context
|
||||
# Yes this is an exec, yes it is potentially bad. Since we limit what variables are
|
||||
# available here, and these policies can only be edited by admins, this is a risk
|
||||
|
@ -221,13 +241,8 @@ class BaseEvaluator:
|
|||
|
||||
def validate(self, expression: str) -> bool:
|
||||
"""Validate expression's syntax, raise ValidationError if Syntax is invalid"""
|
||||
param_keys = self._context.keys()
|
||||
try:
|
||||
compile(
|
||||
self.wrap_expression(expression, param_keys),
|
||||
self._filename,
|
||||
"exec",
|
||||
)
|
||||
self.compile(expression)
|
||||
return True
|
||||
except (ValueError, SyntaxError) as exc:
|
||||
raise ValidationError(f"Expression Syntax Error: {str(exc)}") from exc
|
||||
|
|
19
poetry.lock
generated
19
poetry.lock
generated
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
|
@ -3279,6 +3279,21 @@ requests = ">=2.0.0"
|
|||
[package.extras]
|
||||
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "restrictedpython"
|
||||
version = "7.0"
|
||||
description = "RestrictedPython is a defined subset of the Python language which allows to provide a program input into a trusted environment."
|
||||
optional = false
|
||||
python-versions = ">=3.7, <3.13"
|
||||
files = [
|
||||
{file = "RestrictedPython-7.0-py3-none-any.whl", hash = "sha256:8bb40a822090bed9c7b814d69345b0796db70cc86715d141efc937862f37c6d2"},
|
||||
{file = "RestrictedPython-7.0.tar.gz", hash = "sha256:53704afbbc350fdc8fb245441367be671c9f8380869201b2e8452e74fce3db14"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx", "sphinx-rtd-theme"]
|
||||
test = ["pytest", "pytest-mock"]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.7.0"
|
||||
|
@ -4437,4 +4452,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "~3.12"
|
||||
content-hash = "d0fe6ae1be389f8a5ca5112aa90555e2ce0a4f336f07a1da9c43dd521e9d9340"
|
||||
content-hash = "0782627c112f4cefa27fa066eb1e4c9b01882b416690f4e1348f4e61dfe02190"
|
||||
|
|
|
@ -157,6 +157,7 @@ pyjwt = "*"
|
|||
python = "~3.12"
|
||||
pyyaml = "*"
|
||||
requests-oauthlib = "*"
|
||||
restrictedpython = "*"
|
||||
sentry-sdk = "*"
|
||||
service_identity = "*"
|
||||
structlog = "*"
|
||||
|
|
Reference in a new issue