mirror of
https://github.com/laurivosandi/certidude
synced 2026-01-12 17:06:59 +00:00
Refactor codebase
* Replace PyOpenSSL with cryptography.io * Rename constants to const * Drop support for uwsgi * Use systemd to launch certidude server * Signer automatically spawned as part of server * Update requirements.txt * Clean up certidude client configuration handling * Add automatic enroll with Kerberos machine cerdentials
This commit is contained in:
@@ -12,7 +12,7 @@ from certidude.auth import login_required, authorize_admin
|
||||
from certidude.user import User
|
||||
from certidude.decorators import serialize, event_source, csrf_protection
|
||||
from certidude.wrappers import Request, Certificate
|
||||
from certidude import constants, config
|
||||
from certidude import const, config
|
||||
|
||||
logger = logging.getLogger("api")
|
||||
|
||||
@@ -35,7 +35,7 @@ class CertificateAuthorityResource(object):
|
||||
resp.stream = open(config.AUTHORITY_CERTIFICATE_PATH, "rb")
|
||||
resp.append_header("Content-Type", "application/x-x509-ca-cert")
|
||||
resp.append_header("Content-Disposition", "attachment; filename=%s.crt" %
|
||||
constants.HOSTNAME.encode("ascii"))
|
||||
const.HOSTNAME.encode("ascii"))
|
||||
|
||||
|
||||
class SessionResource(object):
|
||||
@@ -112,7 +112,7 @@ class NormalizeMiddleware(object):
|
||||
assert not req.get_param("unicode") or req.get_param("unicode") == u"✓", "Unicode sanity check failed"
|
||||
req.context["remote_addr"] = ipaddress.ip_address(req.env["REMOTE_ADDR"].decode("utf-8"))
|
||||
|
||||
def process_response(self, req, resp, resource):
|
||||
def process_response(self, req, resp, resource=None):
|
||||
# wtf falcon?!
|
||||
if isinstance(resp.location, unicode):
|
||||
resp.location = resp.location.encode("ascii")
|
||||
@@ -125,7 +125,6 @@ def certidude_app():
|
||||
from .request import RequestListResource, RequestDetailResource
|
||||
from .lease import LeaseResource
|
||||
from .whois import WhoisResource
|
||||
from .log import LogResource
|
||||
from .tag import TagResource, TagDetailResource
|
||||
from .cfg import ConfigResource, ScriptResource
|
||||
|
||||
@@ -149,19 +148,6 @@ def certidude_app():
|
||||
if config.USER_CERTIFICATE_ENROLLMENT:
|
||||
app.add_route("/api/bundle/", BundleResource())
|
||||
|
||||
log_handlers = []
|
||||
if config.LOGGING_BACKEND == "sql":
|
||||
from certidude.mysqllog import LogHandler
|
||||
uri = config.cp.get("logging", "database")
|
||||
log_handlers.append(LogHandler(uri))
|
||||
app.add_route("/api/log/", LogResource(uri))
|
||||
elif config.LOGGING_BACKEND == "syslog":
|
||||
from logging.handlers import SyslogHandler
|
||||
log_handlers.append(SysLogHandler())
|
||||
# Browsing syslog via HTTP is obviously not possible out of the box
|
||||
elif config.LOGGING_BACKEND:
|
||||
raise ValueError("Invalid logging.backend = %s" % config.LOGGING_BACKEND)
|
||||
|
||||
if config.TAGGING_BACKEND == "sql":
|
||||
uri = config.cp.get("tagging", "database")
|
||||
app.add_route("/api/tag/", TagResource(uri))
|
||||
@@ -171,23 +157,5 @@ def certidude_app():
|
||||
elif config.TAGGING_BACKEND:
|
||||
raise ValueError("Invalid tagging.backend = %s" % config.TAGGING_BACKEND)
|
||||
|
||||
if config.PUSH_PUBLISH:
|
||||
from certidude.push import PushLogHandler
|
||||
log_handlers.append(PushLogHandler())
|
||||
|
||||
for facility in "api", "cli":
|
||||
logger = logging.getLogger(facility)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
for handler in log_handlers:
|
||||
logger.addHandler(handler)
|
||||
|
||||
logging.getLogger("cli").debug("Started Certidude at %s", constants.FQDN)
|
||||
|
||||
import atexit
|
||||
|
||||
def exit_handler():
|
||||
logging.getLogger("cli").debug("Shutting down Certidude")
|
||||
|
||||
atexit.register(exit_handler)
|
||||
|
||||
return app
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
|
||||
import logging
|
||||
import hashlib
|
||||
from certidude import config, authority
|
||||
|
||||
@@ -36,8 +36,6 @@ join
|
||||
tag on device_tag.tag_id = tag.id
|
||||
join
|
||||
device on device_tag.device_id = device.id
|
||||
where
|
||||
device.cn = %s
|
||||
"""
|
||||
|
||||
|
||||
@@ -63,7 +61,7 @@ class ConfigResource(RelationalMixin):
|
||||
@login_required
|
||||
@authorize_admin
|
||||
def on_get(self, req, resp):
|
||||
return self.iterfetch(SQL_SELECT_RULES)
|
||||
return self.iterfetch(SQL_SELECT_TAGS)
|
||||
|
||||
|
||||
class ScriptResource(RelationalMixin):
|
||||
|
||||
@@ -10,6 +10,9 @@ from certidude.decorators import serialize, csrf_protection
|
||||
from certidude.wrappers import Request, Certificate
|
||||
from certidude.firewall import whitelist_subnets, whitelist_content_types
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
logger = logging.getLogger("api")
|
||||
|
||||
class RequestListResource(object):
|
||||
@@ -29,6 +32,7 @@ class RequestListResource(object):
|
||||
"""
|
||||
|
||||
body = req.stream.read(req.content_length)
|
||||
|
||||
csr = Request(body)
|
||||
|
||||
if not csr.common_name:
|
||||
@@ -38,6 +42,19 @@ class RequestListResource(object):
|
||||
"Bad request",
|
||||
"No common name specified!")
|
||||
|
||||
machine = req.context.get("machine")
|
||||
if machine:
|
||||
if csr.common_name != machine:
|
||||
raise falcon.HTTPBadRequest(
|
||||
"Bad request",
|
||||
"Common name %s differs from Kerberos credential %s!" % (csr.common_name, machine))
|
||||
if csr.signable:
|
||||
# Automatic enroll with Kerberos machine cerdentials
|
||||
resp.set_header("Content-Type", "application/x-x509-user-cert")
|
||||
resp.body = authority.sign(csr, overwrite=True).dump()
|
||||
return
|
||||
|
||||
|
||||
# Check if this request has been already signed and return corresponding certificte if it has been signed
|
||||
try:
|
||||
cert = authority.get_signed(csr.common_name)
|
||||
@@ -51,8 +68,8 @@ class RequestListResource(object):
|
||||
|
||||
# TODO: check for revoked certificates and return HTTP 410 Gone
|
||||
|
||||
# Process automatic signing if the IP address is whitelisted and autosigning was requested
|
||||
if req.get_param_as_bool("autosign"):
|
||||
# Process automatic signing if the IP address is whitelisted, autosigning was requested and certificate can be automatically signed
|
||||
if req.get_param_as_bool("autosign") and csr.signable:
|
||||
for subnet in config.AUTOSIGN_SUBNETS:
|
||||
if req.context.get("remote_addr") in subnet:
|
||||
try:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import falcon
|
||||
import json
|
||||
import logging
|
||||
from certidude import constants
|
||||
from certidude import const
|
||||
from certidude.authority import export_crl, list_revoked
|
||||
from certidude.decorators import MyEncoder
|
||||
from cryptography import x509
|
||||
@@ -21,7 +21,7 @@ class RevocationListResource(object):
|
||||
resp.set_header("Content-Type", "application/x-pkcs7-crl")
|
||||
resp.append_header(
|
||||
"Content-Disposition",
|
||||
("attachment; filename=%s.crl" % constants.HOSTNAME).encode("ascii"))
|
||||
("attachment; filename=%s.crl" % const.HOSTNAME).encode("ascii"))
|
||||
# Convert PEM to DER
|
||||
resp.body = x509.load_pem_x509_crl(export_crl(),
|
||||
default_backend()).public_bytes(Encoding.DER)
|
||||
@@ -29,7 +29,7 @@ class RevocationListResource(object):
|
||||
resp.set_header("Content-Type", "application/x-pem-file")
|
||||
resp.append_header(
|
||||
"Content-Disposition",
|
||||
("attachment; filename=%s-crl.pem" % constants.HOSTNAME).encode("ascii"))
|
||||
("attachment; filename=%s-crl.pem" % const.HOSTNAME).encode("ascii"))
|
||||
resp.body = export_crl()
|
||||
elif req.accept.startswith("application/json"):
|
||||
resp.set_header("Content-Type", "application/json")
|
||||
|
||||
Reference in New Issue
Block a user