# This file is part of django-ca (https://github.com/mathiasertl/django-ca).
#
# django-ca is free software: you can redistribute it and/or modify it under the terms of the GNU General
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# django-ca is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along with django-ca. If not, see
# <http://www.gnu.org/licenses/>.
"""API utility functions."""
import typing
from typing import Any
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.http import Http404
from django_ca.models import Certificate, CertificateAuthority
if typing.TYPE_CHECKING:
from django.contrib.auth.models import User # pylint: disable=imported-auth-user
else:
from django.contrib.auth import get_user_model
User = get_user_model()
# Skip doctests in pytest(-doctestplus), as api/tests_utils.py manually loads tests with database access.
__doctest_skip__ = ["*"]
def get_certificate_authority(serial: str, expired: bool = False) -> CertificateAuthority:
"""Get a certificate authority from the given serial."""
qs = CertificateAuthority.objects.enabled().exclude(api_enabled=False)
if expired is False:
qs = qs.valid()
try:
return qs.get(serial=serial)
except CertificateAuthority.DoesNotExist as ex:
raise Http404(f"{serial}: Certificate authority not found.") from ex
[docs]
@transaction.atomic
def create_api_user(
username: str,
password: str,
view_certificateauthority: bool = True,
change_certificateauthority: bool = True,
sign_certificate: bool = True,
view_certificate: bool = True,
revoke_certificate: bool = True,
**extra_fields: Any,
) -> User:
"""Create an API user capable of using the REST API.
By default, the user will be able to perform all actions provided by the API.
Note that *unlike* :py:meth:`~django:django.contrib.auth.models.UserManager.create_user`, the `password`
argument is the second argument and mandatory. You can still pass an `email` address as keyword argument.
>>> create_api_user("username", "password", revoke_certificate=False, email="user@example.com")
<User: username>
Parameters
----------
username : str
The username for the API user.
password : str
The password for the API user.
view_certificateauthority : bool, optional
If the user is able to list/view certificate authorities via the API.
change_certificateauthority : bool, optional
If the user is able to update certificate authorities via the API.
sign_certificate : bool, optional
If the user is able to sign new certificates via the API.
view_certificate : bool, optional
If the user is able to list/view existing certificates via the API.
revoke_certificate : bool, optional
If the user is able to revoke certificates via the API.
**extra_fields
Any additional keyword arguments are passed to
:py:meth:`~django:django.contrib.auth.models.UserManager.create_user`.
"""
ca_content_type = ContentType.objects.get_for_model(CertificateAuthority)
cert_content_type = ContentType.objects.get_for_model(Certificate)
user = User.objects.create_user(username, password=password, **extra_fields)
permissions = []
if view_certificateauthority is True:
permissions.append(
Permission.objects.get(codename="view_certificateauthority", content_type=ca_content_type)
)
if change_certificateauthority is True:
permissions.append(
Permission.objects.get(codename="change_certificateauthority", content_type=ca_content_type)
)
if sign_certificate is True:
permissions.append(
Permission.objects.get(codename="sign_certificate", content_type=cert_content_type)
)
if view_certificate is True:
permissions.append(
Permission.objects.get(codename="view_certificate", content_type=cert_content_type)
)
if revoke_certificate is True:
permissions.append(
Permission.objects.get(codename="revoke_certificate", content_type=cert_content_type)
)
user.user_permissions.add(*permissions)
return user