Skip to content

Commit

Permalink
Add bsn validation to mock login form
Browse files Browse the repository at this point in the history
  • Loading branch information
pi-sigma committed Oct 23, 2023
1 parent e919dd6 commit 8c56182
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
7 changes: 6 additions & 1 deletion digid_eherkenning/mock/idp/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from django import forms
from django.utils.translation import gettext_lazy as _

from ...validators import BSNValidator


class PasswordLoginForm(forms.Form):
auth_name = forms.CharField(
max_length=255, required=True, label=_("DigiD gebruikersnaam")
max_length=255,
required=True,
label=_("DigiD gebruikersnaam"),
validators=[BSNValidator()],
)
auth_pass = forms.CharField(
max_length=255, required=True, label=_("Wachtwoord"), widget=forms.PasswordInput
Expand Down
54 changes: 54 additions & 0 deletions digid_eherkenning/validators.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,62 @@
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _

# See `OINType` in eherkenning-dc.xml XSD
oin_validator = RegexValidator(
regex=r"[0-9]{20}",
message=_("A valid OIN consists of 20 digits."),
)


validate_digits = RegexValidator(
regex="^[0-9]+$", message=_("Expected a numerical value.")
)


class Proef11ValidatorBase:
value_size = NotImplemented
error_messages = {
"too_short": NotImplemented,
"wrong": NotImplemented,
}

def __call__(self, value):
"""
Validates that a string value is a valid 11-proef number (BSN, RSIN etc) by applying the
'11-proef' checking.
:param value: String object representing a presumably good 11-proef number.
"""
# Initial sanity checks.
validate_digits(value)
if len(value) != self.value_size:
raise ValidationError(
self.error_messages["too_short"],
params={"size": self.value_size},
code="invalid",
)

# 11-proef check.
total = 0
for multiplier, char in enumerate(reversed(value), start=1):
if multiplier == 1:
total += -multiplier * int(char)
else:
total += multiplier * int(char)

if total % 11 != 0:
raise ValidationError(self.error_messages["wrong"])


@deconstructible
class BSNValidator(Proef11ValidatorBase):
"""
Validate a BSN value by applying the "11-proef".
"""

value_size = 9
error_messages = {
"too_short": _("BSN should have %(size)i characters."),
"wrong": _("Invalid BSN."),
}
24 changes: 24 additions & 0 deletions tests/test_mock_forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest

from digid_eherkenning.mock.idp.forms import PasswordLoginForm


@pytest.mark.parametrize(
"auth_name, auth_pass, name_has_error, pass_has_error",
[
("296648875", "password", False, False), # OK
("abcdefghe", "password", True, False), # bsn wrong type
("2966488759", "password", True, False), # bsn too long
("29664887", "password", True, False), # bsn too short
("123456789", "password", True, False), # bsn wrong checksum
("296648875", "", False, True), # missing password
],
)
def test_password_login_form_validate(
auth_name, auth_pass, name_has_error, pass_has_error
):
form = PasswordLoginForm(data={"auth_name": auth_name, "auth_pass": auth_pass})

assert form.has_error("auth_name") is name_has_error
assert form.has_error("auth_pass") is pass_has_error
assert form.is_valid() is not (name_has_error or pass_has_error)

0 comments on commit 8c56182

Please sign in to comment.