Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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