-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[api] Rest API for PKI app #455
Changes from all commits
ec92a99
9f15ab7
443402e
0f40be5
84d02a5
0bfe2d9
55e1e35
7d958a1
3b7674b
b8661e0
466da67
a93805c
625738a
cecd615
2ccb28b
683d690
195b7d8
c89a5ac
7d12010
5231b83
f96ba4e
1b1b9e6
45db198
d67ae09
ae42efc
44fed3c
738aa63
6130f5a
91cd457
4bf3fa4
d386202
9abbb5c
a020222
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -952,7 +952,8 @@ Download template configuration | |
|
||
GET /api/v1/controller/template/{id}/configuration/ | ||
|
||
The above endpoint triggers the download of a ``tar.gz`` file containing the generated configuration for that specific template. | ||
The above endpoint triggers the download of a ``tar.gz`` file | ||
containing the generated configuration for that specific template. | ||
|
||
Change details of template | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
@@ -1003,7 +1004,8 @@ Download VPN configuration | |
|
||
GET /api/v1/controller/vpn/{id}/configuration/ | ||
|
||
The above endpoint triggers the download of a ``tar.gz`` file containing the generated configuration for that specific VPN. | ||
The above endpoint triggers the download of a ``tar.gz`` file | ||
containing the generated configuration for that specific VPN. | ||
|
||
Change details of VPN | ||
^^^^^^^^^^^^^^^^^^^^^ | ||
|
@@ -1026,6 +1028,143 @@ Delete VPN | |
|
||
DELETE /api/v1/controller/vpn/{id}/ | ||
|
||
List CA | ||
^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
GET /api/v1/controller/ca/ | ||
|
||
Create new CA | ||
^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/ca/ | ||
|
||
Import existing CA | ||
^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/ca/ | ||
|
||
**Note**: To import an existing CA, only ``name``, ``certificate`` | ||
and ``private_key`` fields have to be filled in the ``HTML`` form or | ||
included in the ``JSON`` format. | ||
|
||
Get CA Detail | ||
^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
GET /api/v1/controller/ca/{id}/ | ||
|
||
Change details of CA | ||
^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
PUT /api/v1/controller/ca/{id}/ | ||
|
||
Patch details of CA | ||
^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
PATCH /api/v1/controller/ca/{id}/ | ||
|
||
Download CA(crl) | ||
^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
GET /api/v1/controller/ca/{id}/crl/ | ||
|
||
The above endpoint triggers the download of ``{id}.crl`` file containing | ||
up to date CRL of that specific CA. | ||
|
||
Delete CA | ||
^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
DELETE /api/v1/controller/ca/{id}/ | ||
|
||
Renew CA | ||
^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/ca/{id}/renew/ | ||
|
||
List Cert | ||
^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
GET /api/v1/controller/cert/ | ||
|
||
Create new Cert | ||
^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/cert/ | ||
|
||
Import existing Cert | ||
^^^^^^^^^^^^^^^^^^^^ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you please spend a few words here to explain how to import a cert (specify the fields required to make the import cert work)? |
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/cert/ | ||
|
||
**Note**: To import an existing Cert, only ``name``, ``ca``, | ||
``certificate`` and ``private_key`` fields have to be filled | ||
in the ``HTML`` form or included in the ``JSON`` format. | ||
|
||
Get Cert Detail | ||
^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
GET /api/v1/controller/cert/{id}/ | ||
|
||
Change details of Cert | ||
^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
PUT /api/v1/controller/cert/{id}/ | ||
|
||
Patch details of Cert | ||
^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
PATCH /api/v1/controller/cert/{id}/ | ||
|
||
Delete Cert | ||
^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
DELETE /api/v1/controller/cert/{id}/ | ||
|
||
Renew Cert | ||
^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/cert/{id}/renew/ | ||
|
||
Revoke Cert | ||
^^^^^^^^^^^ | ||
|
||
.. code-block:: text | ||
|
||
POST /api/v1/controller/cert/{id}/revoke/ | ||
|
||
Default Alerts / Notifications | ||
------------------------------ | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
from django.utils.translation import ugettext_lazy as _ | ||
from django_x509.base.models import ( | ||
default_ca_validity_end, | ||
default_cert_validity_end, | ||
default_validity_start, | ||
) | ||
from rest_framework import serializers | ||
from swapper import load_model | ||
|
||
from openwisp_users.api.mixins import FilterSerializerByOrgManaged | ||
from openwisp_utils.api.serializers import ValidatedModelSerializer | ||
|
||
Ca = load_model('django_x509', 'Ca') | ||
Cert = load_model('django_x509', 'Cert') | ||
|
||
|
||
class BaseSerializer(FilterSerializerByOrgManaged, ValidatedModelSerializer): | ||
pass | ||
|
||
|
||
class BaseListSerializer(BaseSerializer): | ||
extensions = serializers.JSONField( | ||
initial=[], | ||
help_text=_('additional x509 certificate extensions'), | ||
required=False, | ||
) | ||
|
||
def get_import_data_hook(self, instance): | ||
return get_import_data(instance) | ||
|
||
def validate(self, data): | ||
instance = self.instance or self.Meta.model(**data) | ||
instance.full_clean() | ||
if data.get('certificate') and data.get('private_key'): | ||
data = self.get_import_data_hook(instance) | ||
return data | ||
|
||
def validate_validity_start(self, value): | ||
if value is None: | ||
value = default_validity_start() | ||
return value | ||
|
||
def default_validity_end_hook(self): | ||
return default_ca_validity_end() | ||
|
||
def validate_validity_end(self, value): | ||
if value is None: | ||
value = self.default_validity_end_hook() | ||
return value | ||
|
||
|
||
class CaListSerializer(BaseListSerializer): | ||
class Meta: | ||
model = Ca | ||
fields = [ | ||
'id', | ||
'name', | ||
'organization', | ||
'notes', | ||
'key_length', | ||
'digest', | ||
'validity_start', | ||
'validity_end', | ||
ManishShah120 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
'country_code', | ||
'state', | ||
'city', | ||
'organization_name', | ||
'organizational_unit_name', | ||
'email', | ||
'common_name', | ||
'extensions', | ||
'serial_number', | ||
'certificate', | ||
'private_key', | ||
'passphrase', | ||
'created', | ||
'modified', | ||
] | ||
read_only_fields = ['created', 'modified'] | ||
extra_kwargs = { | ||
'organization': {'required': True}, | ||
'key_length': {'initial': '2048'}, | ||
'digest': {'initial': 'sha256'}, | ||
'passphrase': {'write_only': True}, | ||
'validity_start': {'default': default_validity_start()}, | ||
'validity_end': {'default': default_ca_validity_end()}, | ||
} | ||
|
||
|
||
def get_ca_detail_fields(fields): | ||
""" | ||
Returns the fields for the `CADetailSerializer`. | ||
""" | ||
fields.remove('passphrase') | ||
return fields | ||
|
||
|
||
class CaDetailSerializer(BaseSerializer): | ||
extensions = serializers.JSONField(read_only=True) | ||
|
||
class Meta: | ||
model = Ca | ||
fields = get_ca_detail_fields(CaListSerializer.Meta.fields[:]) | ||
read_only_fields = fields[4:] | ||
|
||
|
||
class CaRenewSerializer(CaDetailSerializer): | ||
class Meta(CaDetailSerializer.Meta): | ||
read_only_fields = CaDetailSerializer.Meta.fields | ||
|
||
|
||
def get_import_data(instance): | ||
data = { | ||
'name': instance.name, | ||
'organization': instance.organization, | ||
'key_length': instance.key_length, | ||
'digest': instance.digest, | ||
'validity_start': instance.validity_start, | ||
'validity_end': instance.validity_end, | ||
'country_code': instance.country_code, | ||
'state': instance.state, | ||
'city': instance.city, | ||
'organization_name': instance.organization_name, | ||
'organizational_unit_name': instance.organizational_unit_name, | ||
'email': instance.email, | ||
'common_name': instance.common_name, | ||
'extensions': instance.extensions, | ||
'serial_number': instance.serial_number, | ||
'certificate': instance.certificate, | ||
'private_key': instance.private_key, | ||
'passphrase': instance.passphrase, | ||
} | ||
return data | ||
|
||
|
||
def get_cert_list_fields(fields): | ||
""" | ||
Returns the fields for the `CertListSerializer`. | ||
""" | ||
fields.insert(3, 'ca') | ||
fields.insert(5, 'revoked') | ||
fields.insert(6, 'revoked_at') | ||
return fields | ||
|
||
|
||
class CertListSerializer(BaseListSerializer): | ||
include_shared = True | ||
|
||
class Meta: | ||
model = Cert | ||
fields = get_cert_list_fields(CaListSerializer.Meta.fields[:]) | ||
read_only_fields = ['created', 'modified'] | ||
extra_kwargs = { | ||
'revoked': {'read_only': True}, | ||
'revoked_at': {'read_only': True}, | ||
'key_length': {'initial': '2048'}, | ||
'digest': {'initial': 'sha256'}, | ||
'passphrase': {'write_only': True}, | ||
'validity_start': {'default': default_validity_start()}, | ||
'validity_end': {'default': default_cert_validity_end()}, | ||
} | ||
|
||
def get_import_data_hook(self, instance): | ||
data = super().get_import_data_hook(instance) | ||
data.update({'ca': instance.ca}) | ||
return data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this looks mostly the same as the Ca serializer |
||
|
||
def default_validity_end_hook(self): | ||
return default_cert_validity_end() | ||
|
||
|
||
def get_cert_detail_fields(fields): | ||
""" | ||
Returns the fields for the `CertDetailSerializer`. | ||
""" | ||
fields.remove('passphrase') | ||
return fields | ||
|
||
|
||
class CertDetailSerializer(BaseSerializer): | ||
extensions = serializers.JSONField(read_only=True) | ||
|
||
class Meta: | ||
model = Cert | ||
fields = get_cert_detail_fields(CertListSerializer.Meta.fields[:]) | ||
read_only_fields = ['ca'] + fields[5:] | ||
|
||
|
||
class CertRevokeRenewSerializer(CertDetailSerializer): | ||
class Meta(CertDetailSerializer.Meta): | ||
read_only_fields = CertDetailSerializer.Meta.fields |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from django.conf import settings | ||
from django.urls import path | ||
|
||
from . import views as api_views | ||
|
||
app_name = 'openwisp_controller' | ||
|
||
|
||
def get_pki_api_urls(api_views): | ||
""" | ||
returns:: all the API urls of the PKI app | ||
""" | ||
if getattr(settings, 'OPENWISP_CONTROLLER_PKI_API', True): | ||
return [ | ||
path('controller/ca/', api_views.ca_list, name='ca_list'), | ||
path('controller/ca/<str:pk>/', api_views.ca_detail, name='ca_detail'), | ||
path('controller/ca/<str:pk>/renew/', api_views.ca_renew, name='ca_renew'), | ||
path( | ||
'controller/ca/<str:pk>/crl', | ||
api_views.crl_download, | ||
name='crl_download', | ||
), | ||
path('controller/cert/', api_views.cert_list, name='cert_list'), | ||
path( | ||
'controller/cert/<str:pk>/', api_views.cert_detail, name='cert_detail' | ||
), | ||
path( | ||
'controller/cert/<str:pk>/revoke/', | ||
api_views.cert_revoke, | ||
name='cert_revoke', | ||
), | ||
path( | ||
'controller/cert/<str:pk>/renew/', | ||
api_views.cert_renew, | ||
name='cert_renew', | ||
), | ||
] | ||
else: | ||
return [] | ||
|
||
|
||
urlpatterns = get_pki_api_urls(api_views) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please spend a few words here to explain how to import a CA (specify the fields required to make the import cert work)?