providers/saml: better handle PropertyMapping evaluation errors

This commit is contained in:
Jens Langhammer 2020-02-18 10:12:42 +01:00
parent aeca66a288
commit 813b2676de
3 changed files with 25 additions and 3 deletions

View File

@ -0,0 +1,5 @@
"""passbook core exceptions"""
class PropertyMappingExpressionException(Exception):
"""Error when a PropertyMapping Exception expression could not be parsed or evaluated."""

View File

@ -5,6 +5,7 @@ from time import sleep
from typing import Optional, Any from typing import Optional, Any
from uuid import uuid4 from uuid import uuid4
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
from jinja2.nativetypes import NativeEnvironment from jinja2.nativetypes import NativeEnvironment
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
@ -18,6 +19,7 @@ from guardian.mixins import GuardianUserMixin
from model_utils.managers import InheritanceManager from model_utils.managers import InheritanceManager
from structlog import get_logger from structlog import get_logger
from passbook.core.exceptions import PropertyMappingExpressionException
from passbook.core.signals import password_changed from passbook.core.signals import password_changed
from passbook.lib.models import CreatedUpdatedModel, UUIDModel from passbook.lib.models import CreatedUpdatedModel, UUIDModel
from passbook.policies.exceptions import PolicyException from passbook.policies.exceptions import PolicyException
@ -303,8 +305,14 @@ class PropertyMapping(UUIDModel):
def evaluate(self, user: User, request: HttpRequest, **kwargs) -> Any: def evaluate(self, user: User, request: HttpRequest, **kwargs) -> Any:
"""Evaluate `self.expression` using `**kwargs` as Context.""" """Evaluate `self.expression` using `**kwargs` as Context."""
try:
expression = NATIVE_ENVIRONMENT.from_string(self.expression) expression = NATIVE_ENVIRONMENT.from_string(self.expression)
except TemplateSyntaxError as exc:
raise PropertyMappingExpressionException from exc
try:
return expression.render(user=user, request=request, **kwargs) return expression.render(user=user, request=request, **kwargs)
except UndefinedError as exc:
raise PropertyMappingExpressionException from exc
def __str__(self): def __str__(self):
return f"Property Mapping {self.name}" return f"Property Mapping {self.name}"

View File

@ -5,6 +5,7 @@ from defusedxml import ElementTree
from django.http import HttpRequest from django.http import HttpRequest
from structlog import get_logger from structlog import get_logger
from passbook.core.exceptions import PropertyMappingExpressionException
from passbook.providers.saml.exceptions import CannotHandleAssertion from passbook.providers.saml.exceptions import CannotHandleAssertion
from passbook.providers.saml.utils import get_random_id from passbook.providers.saml.utils import get_random_id
from passbook.providers.saml.utils.encoding import decode_base64_and_inflate, nice64 from passbook.providers.saml.utils.encoding import decode_base64_and_inflate, nice64
@ -97,7 +98,10 @@ class Processor:
from passbook.providers.saml.models import SAMLPropertyMapping from passbook.providers.saml.models import SAMLPropertyMapping
for mapping in self._remote.property_mappings.all().select_subclasses(): for mapping in self._remote.property_mappings.all().select_subclasses():
if isinstance(mapping, SAMLPropertyMapping): if not isinstance(mapping, SAMLPropertyMapping):
continue
try:
mapping: SAMLPropertyMapping
value = mapping.evaluate( value = mapping.evaluate(
user=self._http_request.user, user=self._http_request.user,
request=self._http_request, request=self._http_request,
@ -107,11 +111,16 @@ class Processor:
"Name": mapping.saml_name, "Name": mapping.saml_name,
"FriendlyName": mapping.friendly_name, "FriendlyName": mapping.friendly_name,
} }
# Normal values and arrays need different dict keys as they are handeled
# differently in the template
if isinstance(value, list): if isinstance(value, list):
mapping_payload["ValueArray"] = value mapping_payload["ValueArray"] = value
else: else:
mapping_payload["Value"] = value mapping_payload["Value"] = value
attributes.append(mapping_payload) attributes.append(mapping_payload)
except PropertyMappingExpressionException as exc:
self._logger.warning(exc)
continue
self._assertion_params["ATTRIBUTES"] = attributes self._assertion_params["ATTRIBUTES"] = attributes
self._assertion_xml = get_assertion_xml( self._assertion_xml = get_assertion_xml(
"saml/xml/assertions/generic.xml", self._assertion_params, signed=True "saml/xml/assertions/generic.xml", self._assertion_params, signed=True