From 81c135ba70919d036027d9ca0de4f39cc21dc7a8 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 16 Jan 2024 15:05:23 +0100 Subject: [PATCH 1/3] Only request X.509 certificates via VICI CRLs or OCSP responses can't be handled at the moment and cause an assertion error. --- strongMan/helper_apps/vici/wrapper/wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strongMan/helper_apps/vici/wrapper/wrapper.py b/strongMan/helper_apps/vici/wrapper/wrapper.py index 060b53f..c120700 100644 --- a/strongMan/helper_apps/vici/wrapper/wrapper.py +++ b/strongMan/helper_apps/vici/wrapper/wrapper.py @@ -102,7 +102,7 @@ def get_certificates(self): :rtype: list ''' certificates = [] - for certificate in self.session.list_certs(): + for certificate in self.session.list_certs({"type": "X509"}): certificates.append(certificate) return certificates From dbb037a35dff0caf3a735798751208cfa1f63d10 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 16 Jan 2024 15:44:02 +0100 Subject: [PATCH 2/3] Handle clicks to remove buttons more generically in certificate view This allows placing more than one button in a form. --- .../static/certificates/details.js | 34 +++++++++++-------- .../templates/certificates/details.html | 4 +-- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/strongMan/apps/certificates/static/certificates/details.js b/strongMan/apps/certificates/static/certificates/details.js index 1de7778..536c477 100644 --- a/strongMan/apps/certificates/static/certificates/details.js +++ b/strongMan/apps/certificates/static/certificates/details.js @@ -1,15 +1,21 @@ -/** - * Created by root on 18/04/16. - */ +jQuery(function($) { + var $remove_btns = $('button.remove-btn'); + $remove_btns.each(function () { + var $btn = $(this); + var $form = $btn.closest('form'); -function removeBtnClicked(form) { - jform = $(form); - btn = jform.find('.remove-btn'); - if (btn.hasClass('btn-default')) { - btn.removeClass('btn-default').addClass('btn-danger'); - btn.find('.removebtn-text').text('Are you sure?'); - return false; - } else { - return true; - } -} + var $submitter = null; + $form.submit(function (form) { + if ($submitter && $submitter[0] == $btn[0] && $btn.hasClass('btn-default')) { + $btn.removeClass('btn-default').addClass('btn-danger'); + $btn.find('.removebtn-text').text('Are you sure?'); + return false; + } else { + return true; + } + }); + $form.find('button[type=submit]').click(function () { + $submitter = $(this); + }); + }); +}); diff --git a/strongMan/apps/certificates/templates/certificates/details.html b/strongMan/apps/certificates/templates/certificates/details.html index 4c0c1af..108ce35 100644 --- a/strongMan/apps/certificates/templates/certificates/details.html +++ b/strongMan/apps/certificates/templates/certificates/details.html @@ -172,7 +172,7 @@

{% if not readonly %}
-
+ {% csrf_token %}
-
- {% if not readonly %} -
- - {% csrf_token %} - - - - +
+
+ {% csrf_token %} +
+ + {% if not readonly %} + + {% endif %}
- {% endif %} +
@@ -214,18 +216,18 @@

-
+
{% csrf_token %} - - - + + +
{% endif %}

-{% endblock content %} \ No newline at end of file +{% endblock content %} diff --git a/strongMan/apps/certificates/views/DetailsHandler.py b/strongMan/apps/certificates/views/DetailsHandler.py index 85c38cb..3229072 100644 --- a/strongMan/apps/certificates/views/DetailsHandler.py +++ b/strongMan/apps/certificates/views/DetailsHandler.py @@ -1,6 +1,9 @@ +import oscrypto.asymmetric +from urllib.parse import quote + from django.contrib import messages from django.urls import reverse -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import render from ..models import UserCertificate, ViciCertificate, CertificateDoNotDelete from ..forms import ChangeNicknameForm @@ -28,11 +31,15 @@ def _render_user_details(self): def handle(self): if self._is_vicicert(): + if self.request.method == "POST" and "export_cert" in self.request.POST: + return self._export_certificate() return self._render_vici_details() if self.request.method == "GET": return self._render_user_details() elif self.request.method == "POST": + if "export_cert" in self.request.POST: + return self._export_certificate() if "remove_cert" in self.request.POST: return self._delete_cert() elif "remove_privatekey" in self.request.POST: @@ -78,3 +85,17 @@ def _delete_private_key(self): messages.add_message(self.request, messages.ERROR, "Can't delete private key. " + str(e)) return self._render_user_details() + + def _export_certificate(self): + try: + cert = oscrypto.asymmetric.load_certificate(self.certificate.der_container) + pem_bytes = oscrypto.asymmetric.dump_certificate(cert) + + filename = quote(self._vicicert.nickname if self._is_vicicert() else self._usercert.nickname) + + response = HttpResponse(pem_bytes, content_type="application/x-pem-file") + response['Content-Disposition'] = "attachment; filename*=utf-8''%s.pem" % filename + return response + except Exception as e: + messages.add_message(self.request, messages.ERROR, "Couldn't export the cert. " + str(e)) + return self._render_user_details()