Skip to content

Commit

Permalink
✨ [#4320] Don't emit cosign login options if a link is used in the email
Browse files Browse the repository at this point in the history
Users who have the link in the email are directly taken to the
right place to start the cosign process. This obsoletes the
entrypoint at the form start, and by not returning any login options
for cosign, we prevent this block from appearing in the frontend.

Detection of a link is used or not is done by checking for the
presence of the 'form_url' context variable in the request
email template.
  • Loading branch information
sergei-maertens committed Nov 1, 2024
1 parent ebd25dc commit 0251eb6
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 5 deletions.
17 changes: 14 additions & 3 deletions src/openforms/authentication/api/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from openforms.authentication.api.serializers import LoginOptionSerializer
from openforms.authentication.registry import register as auth_register
from openforms.config.models import GlobalConfiguration
from openforms.forms.models import Form


class LoginOptionsReadOnlyField(serializers.ListField):
Expand All @@ -24,7 +26,16 @@ def __init__(self, is_for_cosign: bool = False, *args, **kwargs) -> None:
def to_internal_value(self, data):
raise NotImplementedError("read only")

def to_representation(self, form):
def to_representation(self, value: Form): # type: ignore reportIncompatibleOverride
request: Request = self.context["request"]
temp = auth_register.get_options(request, form, self.is_for_cosign)
return super().to_representation(temp)

options = auth_register.get_options(request, value, self.is_for_cosign)

# Returning no auth options for cosign if a link is used in the email template
# results in the cosign block not being shown in the frontend.
if self.is_for_cosign:
config = GlobalConfiguration.get_solo()
if config.cosign_request_template_has_link:
options = []

return super().to_representation(options)
13 changes: 12 additions & 1 deletion src/openforms/config/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
from openforms.data_removal.constants import RemovalMethods
from openforms.emails.validators import URLSanitationValidator
from openforms.payments.validators import validate_payment_order_id_template
from openforms.template import openforms_backend, render_from_string
from openforms.template import (
extract_variables_used,
openforms_backend,
render_from_string,
)
from openforms.template.validators import DjangoTemplateValidator
from openforms.translations.utils import ensure_default_language
from openforms.utils.fields import SVGOrImageField
Expand Down Expand Up @@ -599,3 +603,10 @@ def get_default_theme(self) -> Theme:
if none is configured.
"""
return self.default_theme or Theme()

@property
def cosign_request_template_has_link(self) -> bool:
variables_used = extract_variables_used(
self.cosign_request_template, backend=openforms_backend
)
return "form_url" in variables_used
72 changes: 71 additions & 1 deletion src/openforms/forms/tests/test_serializers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from unittest.mock import patch

from django.contrib.auth.models import AnonymousUser
from django.test import RequestFactory, TestCase

from hypothesis import given
from hypothesis.extra.django import TestCase as HypothesisTestCase

from openforms.accounts.tests.factories import UserFactory
from openforms.config.models.config import GlobalConfiguration
from openforms.forms.api.datastructures import FormVariableWrapper
from openforms.forms.api.serializers import FormSerializer
from openforms.forms.api.serializers.logic.action_serializers import (
Expand Down Expand Up @@ -124,7 +126,13 @@ def test_invalid_action(self):


class FormSerializerTest(TestCase):
def test_form_with_cosign(self):
@patch(
"openforms.authentication.api.fields.GlobalConfiguration.get_solo",
return_value=GlobalConfiguration(
cosign_request_template="{{ form_name }} cosign request."
),
)
def test_form_with_cosign(self, mock_get_solo):
form_step = FormStepFactory.create(
form__slug="form-with-cosign",
form__authentication_backends=["digid"],
Expand Down Expand Up @@ -154,6 +162,68 @@ def test_form_with_cosign(self):
self.assertIsNotNone(cosign_login_info)
self.assertEqual(cosign_login_info["identifier"], "digid")

@patch(
"openforms.authentication.api.fields.GlobalConfiguration.get_solo",
return_value=GlobalConfiguration(
cosign_request_template="{{ form_name }} cosign request."
),
)
def test_form_without_cosign_link_used_in_email(self, mock_get_solo):
form_step = FormStepFactory.create(
form__slug="form-with-cosign",
form__authentication_backends=["digid"],
form_definition__configuration={
"components": [
{
"key": "cosignField",
"label": "Cosign",
"type": "cosign",
}
]
},
)
factory = RequestFactory()
request = factory.get("/foo")
request.user = AnonymousUser()

serializer = FormSerializer(
instance=form_step.form, context={"request": request}
)

cosign_login_options = serializer.data["cosign_login_options"]
self.assertEqual(len(cosign_login_options), 1)

@patch(
"openforms.authentication.api.fields.GlobalConfiguration.get_solo",
return_value=GlobalConfiguration(
cosign_request_template="{{ form_url }} cosign request."
),
)
def test_form_with_cosign_link_used_in_email(self, mock_get_solo):
form_step = FormStepFactory.create(
form__slug="form-with-cosign",
form__authentication_backends=["digid"],
form_definition__configuration={
"components": [
{
"key": "cosignField",
"label": "Cosign",
"type": "cosign",
}
]
},
)
factory = RequestFactory()
request = factory.get("/foo")
request.user = AnonymousUser()

serializer = FormSerializer(
instance=form_step.form, context={"request": request}
)

cosign_login_options = serializer.data["cosign_login_options"]
self.assertEqual(len(cosign_login_options), 0)

def test_form_without_cosign(self):
form_step = FormStepFactory.create(
form__slug="form-without-cosign",
Expand Down

0 comments on commit 0251eb6

Please sign in to comment.