67 lines
3.2 KiB
Python
67 lines
3.2 KiB
Python
import falcon
|
|
import logging
|
|
import re
|
|
from asn1crypto import pem
|
|
from asn1crypto.csr import CertificationRequest
|
|
from pinecrypt.server import const, errors, authority
|
|
from pinecrypt.server.decorators import serialize
|
|
from pinecrypt.server.user import User
|
|
from .utils.firewall import login_required, authorize_admin
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class TokenResource(object):
|
|
def __init__(self, manager):
|
|
self.manager = manager
|
|
|
|
def on_put(self, req, resp):
|
|
try:
|
|
username, mail, created, expires, profile = self.manager.consume(req.get_param("token", required=True))
|
|
except errors.TokenDoesNotExist:
|
|
raise falcon.HTTPForbidden("Forbidden", "No such token or token expired")
|
|
body = req.stream.read(req.content_length)
|
|
header, _, der_bytes = pem.unarmor(body)
|
|
csr = CertificationRequest.load(der_bytes)
|
|
|
|
try:
|
|
common_name = csr["certification_request_info"]["subject"].native["common_name"]
|
|
except KeyError:
|
|
logger.info("Malformed certificate signing request without common name token submitted from %s" % req.context["remote"]["addr"])
|
|
raise falcon.HTTPBadRequest(title="Bad request",description="Common name missing from certificate signing request token")
|
|
|
|
if not re.match(const.RE_COMMON_NAME, common_name):
|
|
raise falcon.HTTPBadRequest("Bad request", "Invalid common name %s" % common_name)
|
|
|
|
try:
|
|
mongo_doc = authority.store_request(body, overwrite=const.TOKEN_OVERWRITE_PERMITTED,
|
|
namespace="%s.%s" % (username, const.USER_NAMESPACE), address=str(req.context["remote"]["addr"]))
|
|
_, resp.text = authority.sign(mongo_id=str(mongo_doc["_id"]), profile=profile,
|
|
overwrite=const.TOKEN_OVERWRITE_PERMITTED,
|
|
namespace="%s.%s" % (username, const.USER_NAMESPACE))
|
|
resp.set_header("Content-Type", "application/x-pem-file")
|
|
logger.info("Autosigned %s as proven by token ownership", common_name)
|
|
except errors.DuplicateCommonNameError:
|
|
logger.info("Another request with same common name already exists", common_name)
|
|
raise falcon.HTTPConflict(
|
|
title="CSR with such common name (CN) already exists",
|
|
description="Will not overwrite existing certificate signing request, explicitly delete existing one and try again")
|
|
except FileExistsError:
|
|
logger.info("Won't autosign duplicate %s", common_name)
|
|
raise falcon.HTTPConflict(
|
|
"Certificate with such common name (CN) already exists",
|
|
"Will not overwrite existing certificate signing request, explicitly delete existing one and try again")
|
|
|
|
|
|
@serialize
|
|
@login_required
|
|
@authorize_admin
|
|
def on_post(self, req, resp):
|
|
username = req.get_param("username", required=True)
|
|
if not re.match(const.RE_USERNAME, username):
|
|
raise falcon.HTTPBadRequest("Bad request", "Invalid username")
|
|
# TODO: validate e-mail
|
|
self.manager.issue(
|
|
issuer=req.context.get("user"),
|
|
subject=User.objects.get(username),
|
|
subject_mail=req.get_param("mail"))
|