Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ Changelog
Version 1.4.0 [unreleased]
--------------------------

Work in progress.
Changes
~~~~~~~

- Added schema-backed validation and a simplified admin editor for CA and
certificate extensions.

Version 1.3.0 [2025-10-23]
--------------------------
Expand Down
47 changes: 47 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,53 @@ for new end-entity certificates.

Value of the ``keyUsage`` x509 extension for new end-entity certificates.

``DJANGO_X509_CA_EXTENSIONS_SCHEMA``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

============ =================================
**type**: ``dict``
**default**: bundled CA extensions JSON schema
============ =================================

JSON schema used to validate the ``extensions`` field of CA objects and to
drive the simplified admin editor.

The default schema exposes:

- ``nsComment``
- ``nsCertType`` with CA-oriented values (``sslca``, ``emailca``,
``objca``)

``DJANGO_X509_CERT_EXTENSIONS_SCHEMA``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

============ ==========================================
**type**: ``dict``
**default**: bundled certificate extensions JSON schema
============ ==========================================

JSON schema used to validate the ``extensions`` field of end-entity
certificates and to drive the simplified admin editor.

The default schema exposes:

- ``nsComment``
- ``nsCertType`` with end-entity values (``client``, ``server``,
``email``, ``objsign``)
- ``extendedKeyUsage``

When these settings are overridden, backend validation follows the
supplied schema during field validation. The current backend still only
accepts the extension names and values implemented by django-x509, so
overrides can tighten validation and customize the editor but do not add
support for arbitrary extension types. The built-in editor supports
schemas that keep the same top-level ``array`` plus ``items.oneOf``
structure used by the defaults; unsupported schemas fall back to the raw
JSON textarea while backend validation still uses the configured schema.

Legacy comma-separated values for multi-value extensions are still
accepted and normalized automatically.

``DJANGO_X509_CRL_PROTECTED``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
18 changes: 18 additions & 0 deletions django_x509/base/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from django_x509 import settings as app_settings

from .widgets import ExtensionsWidget


class X509Form(forms.ModelForm):
OPERATION_CHOICES = (
Expand Down Expand Up @@ -79,6 +81,13 @@ def get_fields(self, request, obj=None):
fields.remove("passphrase")
return fields

def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change=change, **kwargs)
extensions = form.base_fields.get("extensions")
if extensions:
extensions.widget = ExtensionsWidget(schema=self.get_extensions_schema())
return form

def get_context(self, data, ca_count=0, cert_count=0):
context = dict()
if ca_count:
Expand All @@ -103,6 +112,9 @@ def get_context(self, data, ca_count=0, cert_count=0):
context.update({"opts": self.model._meta, "data": data})
return context

def get_extensions_schema(self):
return []


class AbstractCaAdmin(BaseAdmin):
list_filter = ["key_length", "digest", "created"]
Expand Down Expand Up @@ -134,6 +146,9 @@ class AbstractCaAdmin(BaseAdmin):
class Media:
js = ("admin/js/jquery.init.js", "django-x509/js/x509-admin.js")

def get_extensions_schema(self):
return app_settings.get_ca_extensions_schema()

def get_urls(self):
return [
path("<int:pk>.crl", self.crl_view, name="crl"),
Expand Down Expand Up @@ -224,6 +239,9 @@ class AbstractCertAdmin(BaseAdmin):
class Media:
js = ("admin/js/jquery.init.js", "django-x509/js/x509-admin.js")

def get_extensions_schema(self):
return app_settings.get_cert_extensions_schema()

def ca_url(self, obj):
url = reverse(
"admin:{0}_ca_change".format(self.opts.app_label), args=[obj.ca.pk]
Expand Down
Loading
Loading