authentik/passbook/policies/matcher/models.py

84 lines
2.8 KiB
Python

"""user field matcher models"""
import re
from django.db import models
from django.utils.translation import gettext as _
from structlog import get_logger
from passbook.core.models import Policy
from passbook.policies.struct import PolicyRequest, PolicyResult
LOGGER = get_logger()
class FieldMatcherPolicy(Policy):
"""Policy which checks if a field of the User model matches/doesn't match a
certain pattern"""
MATCH_STARTSWITH = "startswith"
MATCH_ENDSWITH = "endswith"
MATCH_CONTAINS = "contains"
MATCH_REGEXP = "regexp"
MATCH_EXACT = "exact"
MATCHES = (
(MATCH_STARTSWITH, _("Starts with")),
(MATCH_ENDSWITH, _("Ends with")),
(MATCH_CONTAINS, _("Contains")),
(MATCH_REGEXP, _("Regexp")),
(MATCH_EXACT, _("Exact")),
)
USER_FIELDS = (
("username", _("Username"),),
("name", _("Name"),),
("email", _("E-Mail"),),
("is_staff", _("Is staff"),),
("is_active", _("Is active"),),
("data_joined", _("Date joined"),),
)
user_field = models.TextField(choices=USER_FIELDS)
match_action = models.CharField(max_length=50, choices=MATCHES)
value = models.TextField()
form = "passbook.policies.matcher.forms.FieldMatcherPolicyForm"
def __str__(self):
description = (
f"{self.name}, user.{self.user_field} {self.match_action} '{self.value}'"
)
if self.name:
description = f"{self.name}: {description}"
return description
def passes(self, request: PolicyRequest) -> PolicyResult:
"""Check if user instance passes this role"""
if not hasattr(request.user, self.user_field):
raise ValueError("Field does not exist")
user_field_value = getattr(request.user, self.user_field, None)
LOGGER.debug(
"Checking field",
value=user_field_value,
action=self.match_action,
should_be=self.value,
)
passes = False
if self.match_action == FieldMatcherPolicy.MATCH_STARTSWITH:
passes = user_field_value.startswith(self.value)
if self.match_action == FieldMatcherPolicy.MATCH_ENDSWITH:
passes = user_field_value.endswith(self.value)
if self.match_action == FieldMatcherPolicy.MATCH_CONTAINS:
passes = self.value in user_field_value
if self.match_action == FieldMatcherPolicy.MATCH_REGEXP:
pattern = re.compile(self.value)
passes = bool(pattern.match(user_field_value))
if self.match_action == FieldMatcherPolicy.MATCH_EXACT:
passes = user_field_value == self.value
return PolicyResult(passes)
class Meta:
verbose_name = _("Field matcher Policy")
verbose_name_plural = _("Field matcher Policies")