certidude/certidude/api/signed.py

59 lines
2.6 KiB
Python

import falcon
import logging
import json
import hashlib
from certidude import authority
from certidude.auth import login_required, authorize_admin
from certidude.decorators import csrf_protection
from xattr import getxattr
logger = logging.getLogger(__name__)
class SignedCertificateDetailResource(object):
def on_get(self, req, resp, cn):
preferred_type = req.client_prefers(("application/json", "application/x-pem-file"))
try:
path, buf, cert, signed, expires = authority.get_signed(cn)
except EnvironmentError:
logger.warning("Failed to serve non-existant certificate %s to %s",
cn, req.context.get("remote_addr"))
raise falcon.HTTPNotFound()
if preferred_type == "application/x-pem-file":
resp.set_header("Content-Type", "application/x-pem-file")
resp.set_header("Content-Disposition", ("attachment; filename=%s.pem" % cn))
resp.body = buf
logger.debug("Served certificate %s to %s as application/x-pem-file",
cn, req.context.get("remote_addr"))
elif preferred_type == "application/json":
resp.set_header("Content-Type", "application/json")
resp.set_header("Content-Disposition", ("attachment; filename=%s.json" % cn))
try:
signer_username = getxattr(path, "user.signature.username").decode("ascii")
except IOError:
signer_username = None
resp.body = json.dumps(dict(
common_name = cn,
signer = signer_username,
serial_number = "%x" % cert.serial_number,
signed = cert["tbs_certificate"]["validity"]["not_before"].native.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
expires = cert["tbs_certificate"]["validity"]["not_after"].native.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
sha256sum = hashlib.sha256(buf).hexdigest()))
logger.debug("Served certificate %s to %s as application/json",
cn, req.context.get("remote_addr"))
else:
logger.debug("Client did not accept application/json or application/x-pem-file")
raise falcon.HTTPUnsupportedMediaType(
"Client did not accept application/json or application/x-pem-file")
@csrf_protection
@login_required
@authorize_admin
def on_delete(self, req, resp, cn):
logger.info("Revoked certificate %s by %s from %s",
cn, req.context.get("user"), req.context.get("remote_addr"))
authority.revoke(cn)