Skip to content

Commit

Permalink
✨ [#74] Update the admin interface
Browse files Browse the repository at this point in the history
Updated the admin pages for DigiD/EH configuration to now point to the
place to add new/extra certificates (or manage existing ones).

The validation before saving now requires that at least one certificate
is defined beforehand, which matches the existing validation rules
that the certificate had to be selected.
  • Loading branch information
sergei-maertens committed Jul 19, 2024
1 parent 4822b96 commit a3d76c3
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 113 deletions.
201 changes: 100 additions & 101 deletions digid_eherkenning/admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from datetime import datetime

from django.contrib import admin
from django.urls import reverse
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from privates.admin import PrivateMediaMixin
from privates.widgets import PrivateFileWidget
from solo.admin import SingletonModelAdmin

from .models import ConfigCertificate, DigidConfiguration, EherkenningConfiguration
from .models.base import BaseConfiguration


class CustomPrivateFileWidget(PrivateFileWidget):
Expand All @@ -18,14 +21,39 @@ class CustomPrivateMediaMixin(PrivateMediaMixin):
private_media_file_widget = CustomPrivateFileWidget


@admin.register(DigidConfiguration)
class DigidConfigurationAdmin(CustomPrivateMediaMixin, SingletonModelAdmin):
readonly_fields = ("idp_service_entity_id",)
fieldsets = (
class BaseAdmin(CustomPrivateMediaMixin, SingletonModelAdmin):
readonly_fields = (
"link_to_certificates",
"idp_service_entity_id",
)
private_media_fields = ("idp_metadata_file",)

@admin.display(description=_("certificates"))
def link_to_certificates(self, obj: BaseConfiguration) -> str:
path = reverse(
"admin:digid_eherkenning_configcertificate_changelist",
current_app=self.admin_site.name,
)
config_type = obj._as_config_type()
qs = ConfigCertificate.objects.filter(config_type=config_type)
url = f"{path}?config_type__exact={config_type}"
return format_html(
'<a href="{url}" target="_blank">{label}</a>',
url=url,
config_type=config_type.value,
label=_("Manage ({count})").format(count=qs.count()),
)


def _fieldset_factory(middle):
"""
Output custom fieldsets (model-specific) between fixed shared field(set)s.
"""
head = [
(
_("X.509 Certificate"),
{
"fields": ("certificate",),
"fields": ("link_to_certificates",),
},
),
(
Expand All @@ -52,18 +80,8 @@ class DigidConfigurationAdmin(CustomPrivateMediaMixin, SingletonModelAdmin):
),
},
),
(
_("Service details"),
{
"fields": (
"service_name",
"service_description",
"requested_attributes",
"attribute_consuming_service_index",
"slo",
),
},
),
]
tail = [
(
_("Organization details"),
{
Expand All @@ -75,99 +93,80 @@ class DigidConfigurationAdmin(CustomPrivateMediaMixin, SingletonModelAdmin):
),
},
),
]

return tuple(head + list(middle) + tail)


@admin.register(DigidConfiguration)
class DigidConfigurationAdmin(BaseAdmin):
fieldsets = _fieldset_factory(
[
(
_("Service details"),
{
"fields": (
"service_name",
"service_description",
"requested_attributes",
"attribute_consuming_service_index",
"slo",
),
},
),
]
)
change_form_template = "admin/digid_eherkenning/digidconfiguration/change_form.html"
private_media_fields = ("idp_metadata_file",)


@admin.register(EherkenningConfiguration)
class EherkenningConfigurationAdmin(CustomPrivateMediaMixin, SingletonModelAdmin):
readonly_fields = ("idp_service_entity_id",)
fieldsets = (
(
_("X.509 Certificate"),
{
"fields": ("certificate",),
},
),
(
_("Identity provider"),
{
"fields": (
"metadata_file_source",
"idp_service_entity_id",
"idp_metadata_file",
),
},
),
(
_("SAML configuration"),
{
"fields": (
"entity_id",
"base_url",
"artifact_resolve_content_type",
"want_assertions_signed",
"want_assertions_encrypted",
"signature_algorithm",
"digest_algorithm",
),
},
),
(
_("Service details"),
{
"fields": (
"service_name",
"service_description",
"oin",
"makelaar_id",
"privacy_policy",
"service_language",
),
},
),
(
_("eHerkenning"),
{
"fields": (
"eh_requested_attributes",
"eh_attribute_consuming_service_index",
"eh_service_uuid",
"eh_service_instance_uuid",
"eh_loa",
),
},
),
(
_("eIDAS"),
{
"fields": (
"no_eidas",
"eidas_requested_attributes",
"eidas_attribute_consuming_service_index",
"eidas_service_uuid",
"eidas_service_instance_uuid",
"eidas_loa",
),
},
),
(
_("Organization details"),
{
"fields": (
"technical_contact_person_telephone",
"technical_contact_person_email",
"organization_url",
"organization_name",
),
},
),
class EherkenningConfigurationAdmin(BaseAdmin):
fieldsets = _fieldset_factory(
[
(
_("Service details"),
{
"fields": (
"service_name",
"service_description",
"oin",
"makelaar_id",
"privacy_policy",
"service_language",
),
},
),
(
_("eHerkenning"),
{
"fields": (
"eh_requested_attributes",
"eh_attribute_consuming_service_index",
"eh_service_uuid",
"eh_service_instance_uuid",
"eh_loa",
),
},
),
(
_("eIDAS"),
{
"fields": (
"no_eidas",
"eidas_requested_attributes",
"eidas_attribute_consuming_service_index",
"eidas_service_uuid",
"eidas_service_instance_uuid",
"eidas_loa",
),
},
),
]
)

change_form_template = (
"admin/digid_eherkenning/eherkenningconfiguration/change_form.html"
)
private_media_fields = ("idp_metadata_file",)


@admin.register(ConfigCertificate)
Expand Down
26 changes: 16 additions & 10 deletions digid_eherkenning/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@
from privates.fields import PrivateMediaFileField
from solo.models import SingletonModel

from ..choices import DigestAlgorithms, SignatureAlgorithms, XMLContentTypes
from ..choices import (
ConfigTypes,
DigestAlgorithms,
SignatureAlgorithms,
XMLContentTypes,
)
from .certificates import ConfigCertificate


class ConfigurationManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related("certificate")


class BaseConfiguration(SingletonModel):
idp_metadata_file = PrivateMediaFileField(
_("identity provider metadata"),
Expand Down Expand Up @@ -157,8 +156,6 @@ class BaseConfiguration(SingletonModel):
max_length=100,
)

objects = ConfigurationManager()

class Meta:
abstract = True

Expand Down Expand Up @@ -234,4 +231,13 @@ def clean(self):

# require that a certificate is configured
if not ConfigCertificate.objects.for_config(self).exists():
raise ValidationError(_("You must select a certificate"))
raise ValidationError(
_(
"You must prepare at least one certificate for the {verbose_name}."
).format(verbose_name=self._meta.verbose_name)
)

@classmethod
def _as_config_type(cls) -> ConfigTypes:
opts = cls._meta
return ConfigTypes(f"{opts.app_label}.{opts.object_name}")
3 changes: 1 addition & 2 deletions digid_eherkenning/models/certificates.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@

class ConfigCertificateQuerySet(models.QuerySet):
def for_config(self, config: _AnyDigiD | _AnyEH):
opts = config._meta
config_type = ConfigTypes(f"{opts.app_label}.{opts.object_name}")
config_type = config._as_config_type()
return self.filter(config_type=config_type)


Expand Down

0 comments on commit a3d76c3

Please sign in to comment.