Skip to content

Commit

Permalink
Merge branch 'main' into web/config-provider
Browse files Browse the repository at this point in the history
* main: (22 commits)
  stages/email: improve error handling for incorrect template syntax (#7758)
  core: bump github.com/go-openapi/strfmt from 0.21.7 to 0.21.8 (#7768)
  website: bump postcss from 8.4.31 to 8.4.32 in /website (#7770)
  web: bump the eslint group in /tests/wdio with 1 update (#7773)
  website: bump @types/react from 18.2.39 to 18.2.41 in /website (#7769)
  web: bump the eslint group in /web with 1 update (#7772)
  website: fix typos in example URLs (#7774)
  root: include ca-certificates in container (#7763)
  root: don't show warning when app has no URLs to import (#7765)
  web: revert storybook (#7764)
  web: bump the eslint group in /web with 2 updates (#7730)
  website: bump @types/react from 18.2.38 to 18.2.39 in /website (#7720)
  web: bump the storybook group in /web with 5 updates (#7750)
  website/blog: fix email syntax (#7753)
  web: bump the wdio group in /tests/wdio with 3 updates (#7751)
  web: bump the babel group in /web with 3 updates (#7741)
  web: bump the sentry group in /web with 2 updates (#7747)
  web: bump pyright from 1.1.337 to 1.1.338 in /web (#7743)
  website: bump the docusaurus group in /website with 9 updates (#7746)
  web: bump rollup from 4.6.0 to 4.6.1 in /web (#7748)
  ...
  • Loading branch information
kensternberg-authentik committed Dec 4, 2023
2 parents 6228931 + 893b837 commit 828b8a8
Show file tree
Hide file tree
Showing 21 changed files with 3,852 additions and 1,757 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ WORKDIR /
# We cannot cache this layer otherwise we'll end up with a bigger image
RUN apt-get update && \
# Required for runtime
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 && \
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 ca-certificates && \
# Required for bootstrap & healtcheck
apt-get install -y --no-install-recommends runit && \
apt-get clean && \
Expand Down
4 changes: 3 additions & 1 deletion authentik/api/v3/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
for _authentik_app in get_apps():
try:
api_urls = import_module(f"{_authentik_app.name}.urls")
except (ModuleNotFoundError, ImportError) as exc:
except ModuleNotFoundError:
continue
except ImportError as exc:
LOGGER.warning("Could not import app's URLs", app_name=_authentik_app.name, exc=exc)
continue
if not hasattr(api_urls, "api_urlpatterns"):
Expand Down
2 changes: 1 addition & 1 deletion authentik/core/api/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):

managed = ReadOnlyField()
component = SerializerMethodField()
icon = ReadOnlyField(source="get_icon")
icon = ReadOnlyField(source="icon_url")

def get_component(self, obj: Source) -> str:
"""Get object component so that we know how to edit the object"""
Expand Down
6 changes: 5 additions & 1 deletion authentik/flows/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ def _get_challenge(self, *args, **kwargs) -> Challenge:
stage_type=self.__class__.__name__, method="get_challenge"
).time(),
):
challenge = self.get_challenge(*args, **kwargs)
try:
challenge = self.get_challenge(*args, **kwargs)
except StageInvalidException as exc:
self.logger.debug("Got StageInvalidException", exc=exc)
return self.executor.stage_invalid()
with Hub.current.start_span(
op="authentik.flow.stage._get_challenge",
description=self.__class__.__name__,
Expand Down
43 changes: 30 additions & 13 deletions authentik/stages/email/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
from django.contrib import messages
from django.http import HttpRequest, HttpResponse
from django.http.request import QueryDict
from django.template.exceptions import TemplateSyntaxError
from django.urls import reverse
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext as _
from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError

from authentik.events.models import Event, EventAction
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.flows.exceptions import StageInvalidException
from authentik.flows.models import FlowDesignation, FlowToken
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
from authentik.lib.utils.errors import exception_to_string
from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mails
from authentik.stages.email.utils import TemplateEmailMessage
Expand Down Expand Up @@ -103,18 +107,27 @@ def send_email(self):
current_stage: EmailStage = self.executor.current_stage
token = self.get_token()
# Send mail to user
message = TemplateEmailMessage(
subject=_(current_stage.subject),
to=[email],
language=pending_user.locale(self.request),
template_name=current_stage.template,
template_context={
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
"user": pending_user,
"expires": token.expires,
},
)
send_mails(current_stage, message)
try:
message = TemplateEmailMessage(
subject=_(current_stage.subject),
to=[email],
language=pending_user.locale(self.request),
template_name=current_stage.template,
template_context={
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
"user": pending_user,
"expires": token.expires,
},
)
send_mails(current_stage, message)
except TemplateSyntaxError as exc:
Event.new(
EventAction.CONFIGURATION_ERROR,
message=_("Exception occurred while rendering E-mail template"),
error=exception_to_string(exc),
template=current_stage.template,
).from_http(self.request)
raise StageInvalidException from exc

def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
# Check if the user came back from the email link to verify
Expand All @@ -135,7 +148,11 @@ def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
return self.executor.stage_invalid()
# Check if we've already sent the initial e-mail
if PLAN_CONTEXT_EMAIL_SENT not in self.executor.plan.context:
self.send_email()
try:
self.send_email()
except StageInvalidException as exc:
self.logger.debug("Got StageInvalidException", exc=exc)
return self.executor.stage_invalid()
self.executor.plan.context[PLAN_CONTEXT_EMAIL_SENT] = True
return super().get(request, *args, **kwargs)

Expand Down
58 changes: 54 additions & 4 deletions authentik/stages/email/tests/test_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@
from shutil import rmtree
from tempfile import mkdtemp, mkstemp
from typing import Any
from unittest.mock import PropertyMock, patch

from django.conf import settings
from django.test import TestCase
from django.core.mail.backends.locmem import EmailBackend
from django.urls import reverse

from authentik.stages.email.models import get_template_choices
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.events.models import Event, EventAction
from authentik.flows.markers import StageMarker
from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.stages.email.models import EmailStage, get_template_choices


def get_templates_setting(temp_dir: str) -> dict[str, Any]:
Expand All @@ -18,11 +27,18 @@ def get_templates_setting(temp_dir: str) -> dict[str, Any]:
return templates_setting


class TestEmailStageTemplates(TestCase):
class TestEmailStageTemplates(FlowTestCase):
"""Email tests"""

def setUp(self) -> None:
self.dir = mkdtemp()
self.dir = Path(mkdtemp())
self.user = create_test_admin_user()

self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
self.stage = EmailStage.objects.create(
name="email",
)
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)

def tearDown(self) -> None:
rmtree(self.dir)
Expand All @@ -38,3 +54,37 @@ def test_custom_template(self):
self.assertEqual(len(choices), 3)
unlink(file)
unlink(file2)

def test_custom_template_invalid_syntax(self):
"""Test with custom template"""
with open(self.dir / Path("invalid.html"), "w+", encoding="utf-8") as _invalid:
_invalid.write("{% blocktranslate %}")
with self.settings(TEMPLATES=get_templates_setting(self.dir)):
self.stage.template = "invalid.html"
plan = FlowPlan(
flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()]
)
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()

url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
with patch(
"authentik.stages.email.models.EmailStage.backend_class",
PropertyMock(return_value=EmailBackend),
):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
error_message="Unknown error",
)
events = Event.objects.filter(action=EventAction.CONFIGURATION_ERROR)
self.assertEqual(len(events), 1)
event = events.first()
self.assertEqual(
event.context["message"], "Exception occurred while rendering E-mail template"
)
self.assertEqual(event.context["template"], "invalid.html")
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-openapi/runtime v0.26.0
github.com/go-openapi/strfmt v0.21.7
github.com/go-openapi/strfmt v0.21.8
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.4.0
github.com/gorilla/handlers v1.5.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k=
github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
github.com/go-openapi/strfmt v0.21.8 h1:VYBUoKYRLAlgKDrIxR/I0lKrztDQ0tuTDrbhLVP8Erg=
github.com/go-openapi/strfmt v0.21.8/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
Expand Down
Loading

0 comments on commit 828b8a8

Please sign in to comment.