From 863deafa5979fa3fd405d43455aadc3909720b72 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:37:06 +0200 Subject: [PATCH 01/30] api: attrib: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/attrib.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 81d04ed..3bbc8ea 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -228,7 +228,7 @@ def certidude_app(log_handlers=[]): app.add_route("/api/token/", TokenResource()) # Extended attributes for scripting etc. - app.add_route("/api/signed/{cn}/attr/", AttributeResource(namespace="machine")) + app.add_route("/api/signed/{cn}/attr/", AttributeResource(authority, namespace="machine")) app.add_route("/api/signed/{cn}/script/", ScriptResource()) # API calls used by pushed events on the JS end diff --git a/certidude/api/attrib.py b/certidude/api/attrib.py index 28c0b50..8e4cd63 100644 --- a/certidude/api/attrib.py +++ b/certidude/api/attrib.py @@ -4,7 +4,7 @@ import logging import re from xattr import setxattr, listxattr, removexattr from datetime import datetime -from certidude import config, authority, push +from certidude import push from certidude.decorators import serialize, csrf_protection from certidude.firewall import whitelist_subject from certidude.auth import login_required, login_optional, authorize_admin @@ -13,7 +13,8 @@ from ipaddress import ip_address logger = logging.getLogger(__name__) class AttributeResource(object): - def __init__(self, namespace): + def __init__(self, authority, namespace): + self.authority = authority self.namespace = namespace @serialize @@ -27,7 +28,7 @@ class AttributeResource(object): Results made available only to lease IP address. """ try: - path, buf, cert, attribs = authority.get_attributes(cn, namespace=self.namespace) + path, buf, cert, attribs = self.authority.get_attributes(cn, namespace=self.namespace) except IOError: raise falcon.HTTPNotFound() else: @@ -38,7 +39,7 @@ class AttributeResource(object): def on_post(self, req, resp, cn): namespace = ("user.%s." % self.namespace).encode("ascii") try: - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) except IOError: raise falcon.HTTPNotFound() else: From 937c81bd5ff7188dac92962690241b75b4669136 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:39:49 +0200 Subject: [PATCH 02/30] api: bootstrap: drop usage of global authority import --- certidude/api/__init__.py | 6 +++--- certidude/api/bootstrap.py | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 3bbc8ea..ff54439 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -9,7 +9,7 @@ import hashlib from datetime import datetime, timedelta from time import sleep from xattr import listxattr, getxattr -from certidude import authority, mailer +from certidude import mailer from certidude.auth import login_required, authorize_admin from certidude.user import User from certidude.decorators import serialize, csrf_protection @@ -202,7 +202,7 @@ class NormalizeMiddleware(object): req.context["remote_addr"] = ipaddress.ip_address(req.access_route[0]) def certidude_app(log_handlers=[]): - from certidude import config + from certidude import authority, config from .signed import SignedCertificateDetailResource from .request import RequestListResource, RequestDetailResource from .lease import LeaseResource, LeaseDetailResource @@ -242,7 +242,7 @@ def certidude_app(log_handlers=[]): app.add_route("/api/lease/", LeaseResource()) # Bootstrap resource - app.add_route("/api/bootstrap/", BootstrapResource()) + app.add_route("/api/bootstrap/", BootstrapResource(authority)) # LEDE image builder resource app.add_route("/api/build/{profile}/{suggested_filename}", ImageBuilderResource()) diff --git a/certidude/api/bootstrap.py b/certidude/api/bootstrap.py index d1ba52d..3e1e746 100644 --- a/certidude/api/bootstrap.py +++ b/certidude/api/bootstrap.py @@ -1,14 +1,17 @@ import logging from certidude.decorators import serialize from certidude.config import cp -from certidude import authority, config, const +from certidude import config, const from jinja2 import Template logger = logging.getLogger(__name__) class BootstrapResource(object): + def __init__(self, authority): + self.authority = authority + def on_get(self, req, resp): resp.body = Template(open(config.BOOTSTRAP_TEMPLATE).read()).render( authority = const.FQDN, - servers = authority.list_server_names()) + servers = self.authority.list_server_names()) From be454d7a656d7de82867e1b68343053c0f9df6ee Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:43:21 +0200 Subject: [PATCH 03/30] api: lease: drop usage of global authority import --- certidude/api/__init__.py | 4 ++-- certidude/api/lease.py | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index ff54439..945a684 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -233,13 +233,13 @@ def certidude_app(log_handlers=[]): # API calls used by pushed events on the JS end app.add_route("/api/signed/{cn}/tag/", TagResource()) - app.add_route("/api/signed/{cn}/lease/", LeaseDetailResource()) + app.add_route("/api/signed/{cn}/lease/", LeaseDetailResource(authority)) # API call used to delete existing tags app.add_route("/api/signed/{cn}/tag/{tag}/", TagDetailResource()) # Gateways can submit leases via this API call - app.add_route("/api/lease/", LeaseResource()) + app.add_route("/api/lease/", LeaseResource(authority)) # Bootstrap resource app.add_route("/api/bootstrap/", BootstrapResource(authority)) diff --git a/certidude/api/lease.py b/certidude/api/lease.py index 7ba1bf9..9b6449b 100644 --- a/certidude/api/lease.py +++ b/certidude/api/lease.py @@ -5,7 +5,7 @@ import logging import os import xattr from datetime import datetime -from certidude import config, authority, push +from certidude import config, push from certidude.auth import login_required, authorize_admin, authorize_server from certidude.decorators import serialize @@ -14,12 +14,15 @@ logger = logging.getLogger(__name__) # TODO: lease namespacing (?) class LeaseDetailResource(object): + def __init__(self, authority): + self.authority = authority + @serialize @login_required @authorize_admin def on_get(self, req, resp, cn): try: - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) return dict( last_seen = xattr.getxattr(path, "user.lease.last_seen").decode("ascii"), inner_address = xattr.getxattr(path, "user.lease.inner_address").decode("ascii"), @@ -30,6 +33,9 @@ class LeaseDetailResource(object): class LeaseResource(object): + def __init__(self, authority): + self.authority = authority + @authorize_server def on_post(self, req, resp): client_common_name = req.get_param("client", required=True) @@ -38,7 +44,7 @@ class LeaseResource(object): if "," in client_common_name: client_common_name, _ = client_common_name.split(",", 1) - path, buf, cert, signed, expires = authority.get_signed(client_common_name) # TODO: catch exceptions + path, buf, cert, signed, expires = self.authority.get_signed(client_common_name) # TODO: catch exceptions if req.get_param("serial") and cert.serial_number != req.get_param_as_int("serial"): # OCSP-ish solution for OpenVPN, not exposed for StrongSwan raise falcon.HTTPForbidden("Forbidden", "Invalid serial number supplied") now = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z" From 7f2729e6f4c9ae46b1a3dee937ab83219064a3ba Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:45:07 +0200 Subject: [PATCH 04/30] api: ocsp: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/ocsp.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 945a684..7b3176f 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -262,7 +262,7 @@ def certidude_app(log_handlers=[]): if config.OCSP_SUBNETS: from .ocsp import OCSPResource - app.add_sink(OCSPResource(), prefix="/api/ocsp") + app.add_sink(OCSPResource(authority), prefix="/api/ocsp") # Set up log handlers if config.LOGGING_BACKEND == "sql": diff --git a/certidude/api/ocsp.py b/certidude/api/ocsp.py index 26c2f4a..e4b6d9a 100644 --- a/certidude/api/ocsp.py +++ b/certidude/api/ocsp.py @@ -6,13 +6,16 @@ from asn1crypto.util import timezone from asn1crypto import cms, algos, x509, ocsp from base64 import b64decode, b64encode from certbuilder import pem_armor_certificate -from certidude import authority, push, config +from certidude import push, config from certidude.firewall import whitelist_subnets from datetime import datetime, timedelta from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError class OCSPResource(object): + def __init__(self, authority): + self.authority = authority + @whitelist_subnets(config.OCSP_SUBNETS) def __call__(self, req, resp): try: @@ -55,14 +58,14 @@ class OCSPResource(object): link_target = os.readlink(os.path.join(config.SIGNED_BY_SERIAL_DIR, "%x.pem" % serial)) assert link_target.startswith("../") assert link_target.endswith(".pem") - path, buf, cert, signed, expires = authority.get_signed(link_target[3:-4]) + path, buf, cert, signed, expires = self.authority.get_signed(link_target[3:-4]) if serial != cert.serial_number: logger.error("Certificate store integrity check failed, %s refers to certificate with serial %x" % (link_target, cert.serial_number)) raise EnvironmentError("Integrity check failed") status = ocsp.CertStatus(name='good', value=None) except EnvironmentError: try: - path, buf, cert, signed, expires, revoked = authority.get_revoked(serial) + path, buf, cert, signed, expires, revoked = self.authority.get_revoked(serial) status = ocsp.CertStatus( name='revoked', value={ @@ -102,7 +105,7 @@ class OCSPResource(object): 'certs': [server_certificate.asn1], 'signature_algorithm': {'algorithm': "sha1_rsa"}, 'signature': asymmetric.rsa_pkcs1v15_sign( - authority.private_key, + self.authority.private_key, response_data.dump(), "sha1" ) From 916afba685feb76774cb1be18fa3e65b8c1e78b8 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:49:46 +0200 Subject: [PATCH 05/30] api: request: drop usage of global authority import --- certidude/api/__init__.py | 4 ++-- certidude/api/request.py | 29 +++++++++++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 7b3176f..445df83 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -220,8 +220,8 @@ def certidude_app(log_handlers=[]): # Certificate authority API calls app.add_route("/api/certificate/", CertificateAuthorityResource()) app.add_route("/api/signed/{cn}/", SignedCertificateDetailResource()) - app.add_route("/api/request/{cn}/", RequestDetailResource()) - app.add_route("/api/request/", RequestListResource()) + app.add_route("/api/request/{cn}/", RequestDetailResource(authority)) + app.add_route("/api/request/", RequestListResource(authority)) app.add_route("/api/", SessionResource()) if config.USER_ENROLLMENT_ALLOWED: # TODO: add token enable/disable flag for config diff --git a/certidude/api/request.py b/certidude/api/request.py index 7424eb9..f918e6e 100644 --- a/certidude/api/request.py +++ b/certidude/api/request.py @@ -1,4 +1,3 @@ - import click import falcon import logging @@ -9,7 +8,7 @@ import hashlib from asn1crypto import pem from asn1crypto.csr import CertificationRequest from base64 import b64decode -from certidude import config, authority, push, errors +from certidude import config, push, errors from certidude.auth import login_required, login_optional, authorize_admin from certidude.decorators import csrf_protection, MyEncoder, serialize from certidude.firewall import whitelist_subnets, whitelist_content_types @@ -28,6 +27,9 @@ curl -f -L -H "Content-type: application/pkcs10" --data-binary @test.csr \ """ class RequestListResource(object): + def __init__(self, authority): + self.authority = authority + @login_optional @whitelist_subnets(config.REQUEST_SUBNETS) @whitelist_content_types("application/pkcs10") @@ -61,7 +63,7 @@ class RequestListResource(object): # Automatic enroll with Kerberos machine cerdentials resp.set_header("Content-Type", "application/x-pem-file") - cert, resp.body = authority._sign(csr, body, overwrite=True) + cert, resp.body = self.authority._sign(csr, body, overwrite=True) logger.info("Automatically enrolled Kerberos authenticated machine %s from %s", machine, req.context.get("remote_addr")) return @@ -72,7 +74,7 @@ class RequestListResource(object): Attempt to renew certificate using currently valid key pair """ try: - path, buf, cert, signed, expires = authority.get_signed(common_name) + path, buf, cert, signed, expires = self.authority.get_signed(common_name) except EnvironmentError: pass # No currently valid certificate for this common name else: @@ -112,7 +114,7 @@ class RequestListResource(object): reasons.append("Renewal requested, but not allowed by authority settings") else: resp.set_header("Content-Type", "application/x-x509-user-cert") - _, resp.body = authority._sign(csr, body, overwrite=True) + _, resp.body = self.authority._sign(csr, body, overwrite=True) logger.info("Renewed certificate for %s", common_name) return @@ -122,12 +124,12 @@ class RequestListResource(object): autosigning was requested and certificate can be automatically signed """ if req.get_param_as_bool("autosign"): - if not authority.server_flags(common_name): + if not self.authority.server_flags(common_name): for subnet in config.AUTOSIGN_SUBNETS: if req.context.get("remote_addr") in subnet: try: resp.set_header("Content-Type", "application/x-pem-file") - _, resp.body = authority._sign(csr, body) + _, resp.body = self.authority._sign(csr, body) logger.info("Autosigned %s as %s is whitelisted", common_name, req.context.get("remote_addr")) return except EnvironmentError: @@ -142,7 +144,7 @@ class RequestListResource(object): # Attempt to save the request otherwise try: - request_path, _, _ = authority.store_request(body, + request_path, _, _ = self.authority.store_request(body, address=str(req.context.get("remote_addr"))) except errors.RequestExists: reasons.append("Same request already uploaded exists") @@ -176,13 +178,16 @@ class RequestListResource(object): class RequestDetailResource(object): + def __init__(self, authority): + self.authority = authority + def on_get(self, req, resp, cn): """ Fetch certificate signing request as PEM """ try: - path, buf, _, submitted = authority.get_request(cn) + path, buf, _, submitted = self.authority.get_request(cn) except errors.RequestDoesNotExist: logger.warning("Failed to serve non-existant request %s to %s", cn, req.context.get("remote_addr")) @@ -206,7 +211,7 @@ class RequestDetailResource(object): resp.body = json.dumps(dict( submitted = submitted, common_name = cn, - server = authority.server_flags(cn), + server = self.authority.server_flags(cn), address = getxattr(path, "user.request.address").decode("ascii"), # TODO: move to authority.py md5sum = hashlib.md5(buf).hexdigest(), sha1sum = hashlib.sha1(buf).hexdigest(), @@ -225,7 +230,7 @@ class RequestDetailResource(object): Sign a certificate signing request """ try: - cert, buf = authority.sign(cn, + cert, buf = self.authority.sign(cn, profile=req.get_param("profile", default="default"), overwrite=True, signer=req.context.get("user").name) @@ -244,7 +249,7 @@ class RequestDetailResource(object): @authorize_admin def on_delete(self, req, resp, cn): try: - authority.delete_request(cn) + self.authority.delete_request(cn) # Logging implemented in the function above except errors.RequestDoesNotExist as e: resp.body = "No certificate signing request for %s found" % cn From 239538371f5cb23b4b72afc61396915268da9606 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:51:27 +0200 Subject: [PATCH 06/30] api: revoked: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/revoked.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 445df83..df4975a 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -250,7 +250,7 @@ def certidude_app(log_handlers=[]): # Add CRL handler if we have any whitelisted subnets if config.CRL_SUBNETS: from .revoked import RevocationListResource - app.add_route("/api/revoked/", RevocationListResource()) + app.add_route("/api/revoked/", RevocationListResource(authority)) # Add SCEP handler if we have any whitelisted subnets if config.SCEP_SUBNETS: diff --git a/certidude/api/revoked.py b/certidude/api/revoked.py index 5851848..07ee0a6 100644 --- a/certidude/api/revoked.py +++ b/certidude/api/revoked.py @@ -4,12 +4,14 @@ import falcon import json import logging from certidude import const, config -from certidude.authority import export_crl, list_revoked from certidude.firewall import whitelist_subnets logger = logging.getLogger(__name__) class RevocationListResource(object): + def __init__(self, authority): + self.authority = authority + @whitelist_subnets(config.CRL_SUBNETS) def on_get(self, req, resp): # Primarily offer DER encoded CRL as per RFC5280 @@ -21,7 +23,7 @@ class RevocationListResource(object): ("attachment; filename=%s.crl" % const.HOSTNAME)) # Convert PEM to DER logger.debug("Serving revocation list (DER) to %s", req.context.get("remote_addr")) - resp.body = export_crl(pem=False) + resp.body = self.authority.export_crl(pem=False) elif req.client_accepts("application/x-pem-file"): if req.get_param_as_bool("wait"): url = config.LONG_POLL_SUBSCRIBE % "crl" @@ -35,7 +37,7 @@ class RevocationListResource(object): "Content-Disposition", ("attachment; filename=%s-crl.pem" % const.HOSTNAME)) logger.debug("Serving revocation list (PEM) to %s", req.context.get("remote_addr")) - resp.body = export_crl() + resp.body = self.authority.export_crl() else: logger.debug("Client %s asked revocation list in unsupported format" % req.context.get("remote_addr")) raise falcon.HTTPUnsupportedMediaType( From 1cfb1b3293793abd7e9eafc9b7f29409f2b8236c Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:53:19 +0200 Subject: [PATCH 07/30] api: scep: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/scep.py | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index df4975a..3902ef4 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -255,7 +255,7 @@ def certidude_app(log_handlers=[]): # Add SCEP handler if we have any whitelisted subnets if config.SCEP_SUBNETS: from .scep import SCEPResource - app.add_route("/api/scep/", SCEPResource()) + app.add_route("/api/scep/", SCEPResource(authority)) # Add sink for serving static files app.add_sink(StaticResource(os.path.join(__file__, "..", "..", "static"))) diff --git a/certidude/api/scep.py b/certidude/api/scep.py index 7c1aa95..57b9115 100644 --- a/certidude/api/scep.py +++ b/certidude/api/scep.py @@ -5,7 +5,7 @@ from asn1crypto import cms, algos, x509 from asn1crypto.core import ObjectIdentifier, SetOf, PrintableString from base64 import b64decode, b64encode from certbuilder import pem_armor_certificate -from certidude import authority, push, config +from certidude import push, config from certidude.firewall import whitelist_subnets from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError @@ -37,11 +37,14 @@ class SCEPBadTime(SCEPError): code = 3 class SCEPBadCertId(SCEPError): code = 4 class SCEPResource(object): + def __init__(self, authority): + self.authority = authority + @whitelist_subnets(config.SCEP_SUBNETS) def on_get(self, req, resp): operation = req.get_param("operation", required=True) if operation.lower() == "getcacert": - resp.body = keys.parse_certificate(authority.certificate_buf).dump() + resp.body = keys.parse_certificate(self.authority.certificate_buf).dump() resp.append_header("Content-Type", "application/x-x509-ca-cert") return @@ -120,17 +123,17 @@ class SCEPResource(object): encrypted_content = encrypted_content_info['encrypted_content'].native recipient, = encrypted_envelope['recipient_infos'] - if recipient.native["rid"]["serial_number"] != authority.certificate.serial_number: + if recipient.native["rid"]["serial_number"] != self.authority.certificate.serial_number: raise SCEPBadCertId() # Since CA private key is not directly readable here, we'll redirect it to signer socket key = asymmetric.rsa_pkcs1v15_decrypt( - authority.private_key, + self.authority.private_key, recipient.native["encrypted_key"]) if len(key) == 8: key = key * 3 # Convert DES to 3DES buf = symmetric.tripledes_cbc_pkcs5_decrypt(key, encrypted_content, iv) - _, _, common_name = authority.store_request(buf, overwrite=True) - cert, buf = authority.sign(common_name, overwrite=True) + _, _, common_name = self.authority.store_request(buf, overwrite=True) + cert, buf = self.authority.sign(common_name, overwrite=True) signed_certificate = asymmetric.load_certificate(buf) content = signed_certificate.asn1.dump() @@ -242,14 +245,14 @@ class SCEPResource(object): 'version': "v1", 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ - 'issuer': authority.certificate.issuer, - 'serial_number': authority.certificate.serial_number, + 'issuer': self.authority.certificate.issuer, + 'serial_number': self.authority.certificate.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': "sha1"}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}), 'signature': asymmetric.rsa_pkcs1v15_sign( - authority.private_key, + self.authority.private_key, b"\x31" + attrs.dump()[1:], "sha1" ) @@ -260,7 +263,7 @@ class SCEPResource(object): 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", - 'certificates': [authority.certificate], + 'certificates': [self.authority.certificate], 'digest_algorithms': [cms.DigestAlgorithm({ 'algorithm': "sha1" })], From 29f3e1fce9336f4e0827f19639b31886075e2e96 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:54:36 +0200 Subject: [PATCH 08/30] api: script: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/script.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 3902ef4..34f5d32 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -229,7 +229,7 @@ def certidude_app(log_handlers=[]): # Extended attributes for scripting etc. app.add_route("/api/signed/{cn}/attr/", AttributeResource(authority, namespace="machine")) - app.add_route("/api/signed/{cn}/script/", ScriptResource()) + app.add_route("/api/signed/{cn}/script/", ScriptResource(authority)) # API calls used by pushed events on the JS end app.add_route("/api/signed/{cn}/tag/", TagResource()) diff --git a/certidude/api/script.py b/certidude/api/script.py index 494e528..18bee8a 100644 --- a/certidude/api/script.py +++ b/certidude/api/script.py @@ -1,7 +1,7 @@ import falcon import logging import os -from certidude import const, config, authority +from certidude import const, config from certidude.decorators import serialize from jinja2 import Environment, FileSystemLoader from certidude.firewall import whitelist_subject @@ -10,9 +10,12 @@ logger = logging.getLogger(__name__) env = Environment(loader=FileSystemLoader(config.SCRIPT_DIR), trim_blocks=True) class ScriptResource(): + def __init__(self, authority): + self.authority = authority + @whitelist_subject def on_get(self, req, resp, cn): - path, buf, cert, attribs = authority.get_attributes(cn) + path, buf, cert, attribs = self.authority.get_attributes(cn) # TODO: are keys unique? named_tags = {} other_tags = [] From 4e50ddfc54132960ed79e9580edb336366379cbf Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:55:42 +0200 Subject: [PATCH 09/30] api: signed: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/signed.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 34f5d32..f093900 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -219,7 +219,7 @@ def certidude_app(log_handlers=[]): # Certificate authority API calls app.add_route("/api/certificate/", CertificateAuthorityResource()) - app.add_route("/api/signed/{cn}/", SignedCertificateDetailResource()) + app.add_route("/api/signed/{cn}/", SignedCertificateDetailResource(authority)) app.add_route("/api/request/{cn}/", RequestDetailResource(authority)) app.add_route("/api/request/", RequestListResource(authority)) app.add_route("/api/", SessionResource()) diff --git a/certidude/api/signed.py b/certidude/api/signed.py index 07ea373..1974ed7 100644 --- a/certidude/api/signed.py +++ b/certidude/api/signed.py @@ -3,7 +3,6 @@ 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 @@ -11,11 +10,14 @@ from xattr import getxattr logger = logging.getLogger(__name__) class SignedCertificateDetailResource(object): + def __init__(self, authority): + self.authority = authority + 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) + path, buf, cert, signed, expires = self.authority.get_signed(cn) except EnvironmentError: logger.warning("Failed to serve non-existant certificate %s to %s", cn, req.context.get("remote_addr")) @@ -55,5 +57,5 @@ class SignedCertificateDetailResource(object): 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) + self.authority.revoke(cn) From 7d514a3bc6872ddc0366d50d716347f50a4fb434 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 12:57:27 +0200 Subject: [PATCH 10/30] api: tag: drop usage of global authority import --- certidude/api/__init__.py | 4 ++-- certidude/api/tag.py | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index f093900..5b16e52 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -232,11 +232,11 @@ def certidude_app(log_handlers=[]): app.add_route("/api/signed/{cn}/script/", ScriptResource(authority)) # API calls used by pushed events on the JS end - app.add_route("/api/signed/{cn}/tag/", TagResource()) + app.add_route("/api/signed/{cn}/tag/", TagResource(authority)) app.add_route("/api/signed/{cn}/lease/", LeaseDetailResource(authority)) # API call used to delete existing tags - app.add_route("/api/signed/{cn}/tag/{tag}/", TagDetailResource()) + app.add_route("/api/signed/{cn}/tag/{tag}/", TagDetailResource(authority)) # Gateways can submit leases via this API call app.add_route("/api/lease/", LeaseResource(authority)) diff --git a/certidude/api/tag.py b/certidude/api/tag.py index a670588..5da02b3 100644 --- a/certidude/api/tag.py +++ b/certidude/api/tag.py @@ -1,18 +1,21 @@ import falcon import logging from xattr import getxattr, removexattr, setxattr -from certidude import authority, push +from certidude import push from certidude.auth import login_required, authorize_admin from certidude.decorators import serialize, csrf_protection logger = logging.getLogger(__name__) class TagResource(object): + def __init__(self, authority): + self.authority = authority + @serialize @login_required @authorize_admin def on_get(self, req, resp, cn): - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) tags = [] try: for tag in getxattr(path, "user.xdg.tags").decode("utf-8").split(","): @@ -30,7 +33,7 @@ class TagResource(object): @login_required @authorize_admin def on_post(self, req, resp, cn): - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) key, value = req.get_param("key", required=True), req.get_param("value", required=True) try: tags = set(getxattr(path, "user.xdg.tags").decode("utf-8").split(",")) @@ -46,11 +49,14 @@ class TagResource(object): class TagDetailResource(object): + def __init__(self, authority): + self.authority = authority + @csrf_protection @login_required @authorize_admin def on_put(self, req, resp, cn, tag): - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) value = req.get_param("value", required=True) try: tags = set(getxattr(path, "user.xdg.tags").decode("utf-8").split(",")) @@ -72,7 +78,7 @@ class TagDetailResource(object): @login_required @authorize_admin def on_delete(self, req, resp, cn, tag): - path, buf, cert, signed, expires = authority.get_signed(cn) + path, buf, cert, signed, expires = self.authority.get_signed(cn) tags = set(getxattr(path, "user.xdg.tags").decode("utf-8").split(",")) tags.remove(tag) if not tags: From f7d138e3030d269e479aea60a9a03e01829f44f1 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:00:23 +0200 Subject: [PATCH 11/30] api: token: drop usage of global authority import --- certidude/api/__init__.py | 2 +- certidude/api/token.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 5b16e52..7035a3d 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -225,7 +225,7 @@ def certidude_app(log_handlers=[]): app.add_route("/api/", SessionResource()) if config.USER_ENROLLMENT_ALLOWED: # TODO: add token enable/disable flag for config - app.add_route("/api/token/", TokenResource()) + app.add_route("/api/token/", TokenResource(authority)) # Extended attributes for scripting etc. app.add_route("/api/signed/{cn}/attr/", AttributeResource(authority, namespace="machine")) diff --git a/certidude/api/token.py b/certidude/api/token.py index 27e2d33..b18b213 100644 --- a/certidude/api/token.py +++ b/certidude/api/token.py @@ -11,12 +11,15 @@ from time import time from certidude import mailer from certidude.decorators import serialize from certidude.user import User -from certidude import config, authority +from certidude import config from certidude.auth import login_required, authorize_admin logger = logging.getLogger(__name__) class TokenResource(object): + def __init__(self, authority): + self.authority = authority + def on_put(self, req, resp): # Consume token now = time() @@ -43,7 +46,7 @@ class TokenResource(object): common_name = csr["certification_request_info"]["subject"].native["common_name"] assert common_name == username or common_name.startswith(username + "@"), "Invalid common name %s" % common_name try: - _, resp.body = authority._sign(csr, body) + _, resp.body = self.authority._sign(csr, body) resp.set_header("Content-Type", "application/x-pem-file") logger.info("Autosigned %s as proven by token ownership", common_name) except FileExistsError: From 4580663608ea33089e2d306279b896c9de5d4cf2 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:09:59 +0200 Subject: [PATCH 12/30] api: Create common AuthorityHandler class with authority attribute --- certidude/api/__init__.py | 15 ++++++++------- certidude/api/utils.py | 3 +++ 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 certidude/api/utils.py diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 7035a3d..63adb2c 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -14,6 +14,7 @@ from certidude.auth import login_required, authorize_admin from certidude.user import User from certidude.decorators import serialize, csrf_protection from certidude import const, config +from .utils import AuthorityHandler logger = logging.getLogger(__name__) @@ -27,7 +28,7 @@ class CertificateAuthorityResource(object): const.HOSTNAME.encode("ascii")) -class SessionResource(object): +class SessionResource(AuthorityHandler): @csrf_protection @serialize @login_required @@ -44,7 +45,7 @@ class SessionResource(object): except IOError: submission_hostname = None yield dict( - server = authority.server_flags(common_name), + server = self.authority.server_flags(common_name), submitted = submitted, common_name = common_name, address = submission_address, @@ -142,7 +143,7 @@ class SessionResource(object): dead = 604800 # Seconds from last activity to consider lease dead, X509 chain broken or machine discarded ), common_name = const.FQDN, - title = authority.certificate.subject.native["common_name"], + title = self.authority.certificate.subject.native["common_name"], mailer = dict( name = config.MAILER_NAME, address = config.MAILER_ADDRESS @@ -151,9 +152,9 @@ class SessionResource(object): user_enrollment_allowed=config.USER_ENROLLMENT_ALLOWED, user_multiple_certificates=config.USER_MULTIPLE_CERTIFICATES, events = config.EVENT_SOURCE_SUBSCRIBE % config.EVENT_SOURCE_TOKEN, - requests=serialize_requests(authority.list_requests), - signed=serialize_certificates(authority.list_signed), - revoked=serialize_revoked(authority.list_revoked), + requests=serialize_requests(self.authority.list_requests), + signed=serialize_certificates(self.authority.list_signed), + revoked=serialize_revoked(self.authority.list_revoked), admin_users = User.objects.filter_admins(), user_subnets = config.USER_SUBNETS or None, autosign_subnets = config.AUTOSIGN_SUBNETS or None, @@ -222,7 +223,7 @@ def certidude_app(log_handlers=[]): app.add_route("/api/signed/{cn}/", SignedCertificateDetailResource(authority)) app.add_route("/api/request/{cn}/", RequestDetailResource(authority)) app.add_route("/api/request/", RequestListResource(authority)) - app.add_route("/api/", SessionResource()) + app.add_route("/api/", SessionResource(authority)) if config.USER_ENROLLMENT_ALLOWED: # TODO: add token enable/disable flag for config app.add_route("/api/token/", TokenResource(authority)) diff --git a/certidude/api/utils.py b/certidude/api/utils.py new file mode 100644 index 0000000..781c48d --- /dev/null +++ b/certidude/api/utils.py @@ -0,0 +1,3 @@ +class AuthorityHandler: + def __init__(self, authority): + self.authority = authority From c9dd058d754f9ab6d19fe127b10dcfd837644bfd Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:10:45 +0200 Subject: [PATCH 13/30] api: Use common AuthorityResource where possible --- certidude/api/bootstrap.py | 6 ++---- certidude/api/lease.py | 11 +++-------- certidude/api/ocsp.py | 6 ++---- certidude/api/request.py | 11 +++-------- certidude/api/revoked.py | 6 ++---- certidude/api/scep.py | 6 ++---- certidude/api/script.py | 6 ++---- certidude/api/signed.py | 6 ++---- certidude/api/tag.py | 6 ++---- certidude/api/token.py | 6 ++---- 10 files changed, 22 insertions(+), 48 deletions(-) diff --git a/certidude/api/bootstrap.py b/certidude/api/bootstrap.py index 3e1e746..3a76950 100644 --- a/certidude/api/bootstrap.py +++ b/certidude/api/bootstrap.py @@ -3,13 +3,11 @@ from certidude.decorators import serialize from certidude.config import cp from certidude import config, const from jinja2 import Template +from .utils import AuthorityHandler logger = logging.getLogger(__name__) -class BootstrapResource(object): - def __init__(self, authority): - self.authority = authority - +class BootstrapResource(AuthorityHandler): def on_get(self, req, resp): resp.body = Template(open(config.BOOTSTRAP_TEMPLATE).read()).render( authority = const.FQDN, diff --git a/certidude/api/lease.py b/certidude/api/lease.py index 9b6449b..a1f6660 100644 --- a/certidude/api/lease.py +++ b/certidude/api/lease.py @@ -8,15 +8,13 @@ from datetime import datetime from certidude import config, push from certidude.auth import login_required, authorize_admin, authorize_server from certidude.decorators import serialize +from .utils import AuthorityHandler logger = logging.getLogger(__name__) # TODO: lease namespacing (?) -class LeaseDetailResource(object): - def __init__(self, authority): - self.authority = authority - +class LeaseDetailResource(AuthorityHandler): @serialize @login_required @authorize_admin @@ -32,10 +30,7 @@ class LeaseDetailResource(object): raise falcon.HTTPNotFound() -class LeaseResource(object): - def __init__(self, authority): - self.authority = authority - +class LeaseResource(AuthorityHandler): @authorize_server def on_post(self, req, resp): client_common_name = req.get_param("client", required=True) diff --git a/certidude/api/ocsp.py b/certidude/api/ocsp.py index e4b6d9a..246c483 100644 --- a/certidude/api/ocsp.py +++ b/certidude/api/ocsp.py @@ -11,11 +11,9 @@ from certidude.firewall import whitelist_subnets from datetime import datetime, timedelta from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError +from .utils import AuthorityHandler -class OCSPResource(object): - def __init__(self, authority): - self.authority = authority - +class OCSPResource(AuthorityHandler): @whitelist_subnets(config.OCSP_SUBNETS) def __call__(self, req, resp): try: diff --git a/certidude/api/request.py b/certidude/api/request.py index f918e6e..014029e 100644 --- a/certidude/api/request.py +++ b/certidude/api/request.py @@ -16,6 +16,7 @@ from datetime import datetime from oscrypto import asymmetric from oscrypto.errors import SignatureError from xattr import getxattr +from .utils import AuthorityHandler logger = logging.getLogger(__name__) @@ -26,10 +27,7 @@ curl -f -L -H "Content-type: application/pkcs10" --data-binary @test.csr \ http://ca.example.lan/api/request/?wait=yes """ -class RequestListResource(object): - def __init__(self, authority): - self.authority = authority - +class RequestListResource(AuthorityHandler): @login_optional @whitelist_subnets(config.REQUEST_SUBNETS) @whitelist_content_types("application/pkcs10") @@ -177,10 +175,7 @@ class RequestListResource(object): cls=MyEncoder) -class RequestDetailResource(object): - def __init__(self, authority): - self.authority = authority - +class RequestDetailResource(AuthorityHandler): def on_get(self, req, resp, cn): """ Fetch certificate signing request as PEM diff --git a/certidude/api/revoked.py b/certidude/api/revoked.py index 07ee0a6..ce19fee 100644 --- a/certidude/api/revoked.py +++ b/certidude/api/revoked.py @@ -5,13 +5,11 @@ import json import logging from certidude import const, config from certidude.firewall import whitelist_subnets +from .utils import AuthorityHandler logger = logging.getLogger(__name__) -class RevocationListResource(object): - def __init__(self, authority): - self.authority = authority - +class RevocationListResource(AuthorityHandler): @whitelist_subnets(config.CRL_SUBNETS) def on_get(self, req, resp): # Primarily offer DER encoded CRL as per RFC5280 diff --git a/certidude/api/scep.py b/certidude/api/scep.py index 57b9115..8fc972f 100644 --- a/certidude/api/scep.py +++ b/certidude/api/scep.py @@ -9,6 +9,7 @@ from certidude import push, config from certidude.firewall import whitelist_subnets from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError +from .utils import AuthorityHandler # Monkey patch asn1crypto @@ -36,10 +37,7 @@ class SCEPBadRequest(SCEPError): code = 2 class SCEPBadTime(SCEPError): code = 3 class SCEPBadCertId(SCEPError): code = 4 -class SCEPResource(object): - def __init__(self, authority): - self.authority = authority - +class SCEPResource(AuthorityHandler): @whitelist_subnets(config.SCEP_SUBNETS) def on_get(self, req, resp): operation = req.get_param("operation", required=True) diff --git a/certidude/api/script.py b/certidude/api/script.py index 18bee8a..ccd7a05 100644 --- a/certidude/api/script.py +++ b/certidude/api/script.py @@ -5,14 +5,12 @@ from certidude import const, config from certidude.decorators import serialize from jinja2 import Environment, FileSystemLoader from certidude.firewall import whitelist_subject +from .utils import AuthorityHandler logger = logging.getLogger(__name__) env = Environment(loader=FileSystemLoader(config.SCRIPT_DIR), trim_blocks=True) -class ScriptResource(): - def __init__(self, authority): - self.authority = authority - +class ScriptResource(AuthorityHandler): @whitelist_subject def on_get(self, req, resp, cn): path, buf, cert, attribs = self.authority.get_attributes(cn) diff --git a/certidude/api/signed.py b/certidude/api/signed.py index 1974ed7..2b42cc6 100644 --- a/certidude/api/signed.py +++ b/certidude/api/signed.py @@ -6,13 +6,11 @@ import hashlib from certidude.auth import login_required, authorize_admin from certidude.decorators import csrf_protection from xattr import getxattr +from .utils import AuthorityHandler logger = logging.getLogger(__name__) -class SignedCertificateDetailResource(object): - def __init__(self, authority): - self.authority = authority - +class SignedCertificateDetailResource(AuthorityHandler): def on_get(self, req, resp, cn): preferred_type = req.client_prefers(("application/json", "application/x-pem-file")) diff --git a/certidude/api/tag.py b/certidude/api/tag.py index 5da02b3..a1e8e85 100644 --- a/certidude/api/tag.py +++ b/certidude/api/tag.py @@ -4,13 +4,11 @@ from xattr import getxattr, removexattr, setxattr from certidude import push from certidude.auth import login_required, authorize_admin from certidude.decorators import serialize, csrf_protection +from .utils import AuthorityHandler logger = logging.getLogger(__name__) -class TagResource(object): - def __init__(self, authority): - self.authority = authority - +class TagResource(AuthorityHandler): @serialize @login_required @authorize_admin diff --git a/certidude/api/token.py b/certidude/api/token.py index b18b213..0bb308c 100644 --- a/certidude/api/token.py +++ b/certidude/api/token.py @@ -13,13 +13,11 @@ from certidude.decorators import serialize from certidude.user import User from certidude import config from certidude.auth import login_required, authorize_admin +from .utils import AuthorityHandler logger = logging.getLogger(__name__) -class TokenResource(object): - def __init__(self, authority): - self.authority = authority - +class TokenResource(AuthorityHandler): def on_put(self, req, resp): # Consume token now = time() From b82a38edee8a27014fbbf925c62f02a8f3d5a301 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:13:46 +0200 Subject: [PATCH 14/30] api: attrib: Drop unused imports --- certidude/api/attrib.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/certidude/api/attrib.py b/certidude/api/attrib.py index 8e4cd63..1b3d948 100644 --- a/certidude/api/attrib.py +++ b/certidude/api/attrib.py @@ -1,14 +1,11 @@ -import click import falcon import logging import re from xattr import setxattr, listxattr, removexattr -from datetime import datetime from certidude import push from certidude.decorators import serialize, csrf_protection from certidude.firewall import whitelist_subject -from certidude.auth import login_required, login_optional, authorize_admin -from ipaddress import ip_address +from certidude.auth import login_required, authorize_admin logger = logging.getLogger(__name__) From 82b8185bc591a30707bcb6cd9c2fd85b3e47d1b2 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:14:19 +0200 Subject: [PATCH 15/30] api: bootstrap: Drop unused imports --- certidude/api/bootstrap.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/certidude/api/bootstrap.py b/certidude/api/bootstrap.py index 3a76950..c69ebed 100644 --- a/certidude/api/bootstrap.py +++ b/certidude/api/bootstrap.py @@ -1,6 +1,4 @@ import logging -from certidude.decorators import serialize -from certidude.config import cp from certidude import config, const from jinja2 import Template from .utils import AuthorityHandler From f90a19deeb9457d303d6e20780542b8578022b05 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:16:10 +0200 Subject: [PATCH 16/30] api: token: Drop unused imports --- certidude/api/token.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/certidude/api/token.py b/certidude/api/token.py index 0bb308c..13ce10a 100644 --- a/certidude/api/token.py +++ b/certidude/api/token.py @@ -1,9 +1,6 @@ -import click import falcon import logging import hashlib -import random -import string from asn1crypto import pem from asn1crypto.csr import CertificationRequest from datetime import datetime From bfcd8ef95b3469e87a8e2e0284f3d5ad716c279a Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:16:22 +0200 Subject: [PATCH 17/30] api: tag: Drop unused imports --- certidude/api/tag.py | 1 - 1 file changed, 1 deletion(-) diff --git a/certidude/api/tag.py b/certidude/api/tag.py index a1e8e85..8ea7454 100644 --- a/certidude/api/tag.py +++ b/certidude/api/tag.py @@ -1,4 +1,3 @@ -import falcon import logging from xattr import getxattr, removexattr, setxattr from certidude import push From a15bdd51db7ef80b337da3d157b2a7f0bf8a6ad6 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:16:39 +0200 Subject: [PATCH 18/30] api: revoked: Drop unused imports --- certidude/api/revoked.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/certidude/api/revoked.py b/certidude/api/revoked.py index ce19fee..fc6f448 100644 --- a/certidude/api/revoked.py +++ b/certidude/api/revoked.py @@ -1,7 +1,4 @@ - -import click import falcon -import json import logging from certidude import const, config from certidude.firewall import whitelist_subnets From 1c6043c6c94e8aa3ecd90313a875ea657bf69b62 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:17:09 +0200 Subject: [PATCH 19/30] api: script: Drop unused imports --- certidude/api/script.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/certidude/api/script.py b/certidude/api/script.py index ccd7a05..dd2066d 100644 --- a/certidude/api/script.py +++ b/certidude/api/script.py @@ -1,8 +1,6 @@ -import falcon import logging import os from certidude import const, config -from certidude.decorators import serialize from jinja2 import Environment, FileSystemLoader from certidude.firewall import whitelist_subject from .utils import AuthorityHandler From 912f5766e402b3bb0b1c1580b9a5567c9ae7ea16 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:17:27 +0200 Subject: [PATCH 20/30] api: lease: Drop unused imports --- certidude/api/lease.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/certidude/api/lease.py b/certidude/api/lease.py index a1f6660..89336a8 100644 --- a/certidude/api/lease.py +++ b/certidude/api/lease.py @@ -1,5 +1,3 @@ - -import click import falcon import logging import os From d476998c9ec5d5c83df81da3f11edcad376bcf55 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:17:35 +0200 Subject: [PATCH 21/30] api: log: Drop unused imports --- certidude/api/log.py | 1 - 1 file changed, 1 deletion(-) diff --git a/certidude/api/log.py b/certidude/api/log.py index 7faaec3..1d925a3 100644 --- a/certidude/api/log.py +++ b/certidude/api/log.py @@ -1,5 +1,4 @@ -from certidude import config from certidude.auth import login_required, authorize_admin from certidude.decorators import serialize from certidude.relational import RelationalMixin From f6c0e1ae85f87602e35587ed1b8d6e62e764f7f9 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:18:56 +0200 Subject: [PATCH 22/30] api: __init__: Drop unused imports and fix broken import --- certidude/api/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/certidude/api/__init__.py b/certidude/api/__init__.py index 63adb2c..f1de85a 100644 --- a/certidude/api/__init__.py +++ b/certidude/api/__init__.py @@ -4,13 +4,10 @@ import falcon import mimetypes import logging import os -import click import hashlib -from datetime import datetime, timedelta -from time import sleep +from datetime import datetime from xattr import listxattr, getxattr -from certidude import mailer -from certidude.auth import login_required, authorize_admin +from certidude.auth import login_required from certidude.user import User from certidude.decorators import serialize, csrf_protection from certidude import const, config @@ -274,7 +271,7 @@ def certidude_app(log_handlers=[]): app.add_route("/api/log/", LogResource(uri)) elif config.LOGGING_BACKEND == "syslog": from logging.handlers import SyslogHandler - log_handlers.append(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) From 8626d78b5c1fbc0de3b34a483b295bcb7546bcbb Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:19:50 +0200 Subject: [PATCH 23/30] api: ocsp: Fix logger --- certidude/api/ocsp.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certidude/api/ocsp.py b/certidude/api/ocsp.py index 246c483..8124a09 100644 --- a/certidude/api/ocsp.py +++ b/certidude/api/ocsp.py @@ -1,6 +1,7 @@ import click import falcon import hashlib +import logging import os from asn1crypto.util import timezone from asn1crypto import cms, algos, x509, ocsp @@ -13,6 +14,8 @@ from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError from .utils import AuthorityHandler +logger = logging.getLogger(__name__) + class OCSPResource(AuthorityHandler): @whitelist_subnets(config.OCSP_SUBNETS) def __call__(self, req, resp): From 167d0cbdfd85c2e5ef7f2e4d9b674c889e637370 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:22:12 +0200 Subject: [PATCH 24/30] api: ocsp: Drop unused imports --- certidude/api/ocsp.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/certidude/api/ocsp.py b/certidude/api/ocsp.py index 8124a09..b9f0b15 100644 --- a/certidude/api/ocsp.py +++ b/certidude/api/ocsp.py @@ -1,17 +1,13 @@ -import click import falcon -import hashlib import logging import os from asn1crypto.util import timezone -from asn1crypto import cms, algos, x509, ocsp -from base64 import b64decode, b64encode -from certbuilder import pem_armor_certificate -from certidude import push, config +from asn1crypto import ocsp +from base64 import b64decode +from certidude import config from certidude.firewall import whitelist_subnets -from datetime import datetime, timedelta -from oscrypto import keys, asymmetric, symmetric -from oscrypto.errors import SignatureError +from datetime import datetime +from oscrypto import asymmetric from .utils import AuthorityHandler logger = logging.getLogger(__name__) From 5439d5560a09e2300b185d06ed660cf9bf0a75ff Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:22:44 +0200 Subject: [PATCH 25/30] api: request: Drop unused imports --- certidude/api/request.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certidude/api/request.py b/certidude/api/request.py index 014029e..c9aab93 100644 --- a/certidude/api/request.py +++ b/certidude/api/request.py @@ -1,7 +1,6 @@ import click import falcon import logging -import ipaddress import json import os import hashlib @@ -10,7 +9,7 @@ from asn1crypto.csr import CertificationRequest from base64 import b64decode from certidude import config, push, errors from certidude.auth import login_required, login_optional, authorize_admin -from certidude.decorators import csrf_protection, MyEncoder, serialize +from certidude.decorators import csrf_protection, MyEncoder from certidude.firewall import whitelist_subnets, whitelist_content_types from datetime import datetime from oscrypto import asymmetric From 2eb93e669840147ecd466e36744536badd42f02a Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 13:25:34 +0200 Subject: [PATCH 26/30] api: scep: Drop unused imports --- certidude/api/scep.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/certidude/api/scep.py b/certidude/api/scep.py index 8fc972f..2c0f59c 100644 --- a/certidude/api/scep.py +++ b/certidude/api/scep.py @@ -1,11 +1,9 @@ -import click import hashlib import os -from asn1crypto import cms, algos, x509 -from asn1crypto.core import ObjectIdentifier, SetOf, PrintableString -from base64 import b64decode, b64encode -from certbuilder import pem_armor_certificate -from certidude import push, config +from asn1crypto import cms, algos +from asn1crypto.core import SetOf, PrintableString +from base64 import b64decode +from certidude import config from certidude.firewall import whitelist_subnets from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError @@ -31,7 +29,7 @@ cms.CMSAttribute._oid_specs['recipient_nonce'] = cms.SetOfOctetString cms.CMSAttribute._oid_specs['trans_id'] = SetOfPrintableString class SCEPError(Exception): code = 25 # system failure -class SCEPBadAlg(SCEPError): code = 0 +class SCEPBadAlgo(SCEPError): code = 0 class SCEPBadMessageCheck(SCEPError): code = 1 class SCEPBadRequest(SCEPError): code = 2 class SCEPBadTime(SCEPError): code = 3 From 2f0569abb4732b64b061b042358d0c42031de8a8 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 14:30:47 +0200 Subject: [PATCH 27/30] Move certidude.firewall to api.utils.firewall where it belongs --- certidude/api/attrib.py | 3 ++- certidude/api/ocsp.py | 2 +- certidude/api/request.py | 2 +- certidude/api/revoked.py | 2 +- certidude/api/scep.py | 2 +- certidude/api/script.py | 2 +- certidude/api/{utils.py => utils/__init__.py} | 0 certidude/{ => api/utils}/firewall.py | 0 certidude/auth.py | 1 - 9 files changed, 7 insertions(+), 7 deletions(-) rename certidude/api/{utils.py => utils/__init__.py} (100%) rename certidude/{ => api/utils}/firewall.py (100%) diff --git a/certidude/api/attrib.py b/certidude/api/attrib.py index 1b3d948..fde9931 100644 --- a/certidude/api/attrib.py +++ b/certidude/api/attrib.py @@ -4,9 +4,10 @@ import re from xattr import setxattr, listxattr, removexattr from certidude import push from certidude.decorators import serialize, csrf_protection -from certidude.firewall import whitelist_subject from certidude.auth import login_required, authorize_admin +from .utils.firewall import whitelist_subject + logger = logging.getLogger(__name__) class AttributeResource(object): diff --git a/certidude/api/ocsp.py b/certidude/api/ocsp.py index b9f0b15..508fb20 100644 --- a/certidude/api/ocsp.py +++ b/certidude/api/ocsp.py @@ -5,10 +5,10 @@ from asn1crypto.util import timezone from asn1crypto import ocsp from base64 import b64decode from certidude import config -from certidude.firewall import whitelist_subnets from datetime import datetime from oscrypto import asymmetric from .utils import AuthorityHandler +from .utils.firewall import whitelist_subnets logger = logging.getLogger(__name__) diff --git a/certidude/api/request.py b/certidude/api/request.py index c9aab93..e2d0640 100644 --- a/certidude/api/request.py +++ b/certidude/api/request.py @@ -10,12 +10,12 @@ from base64 import b64decode from certidude import config, push, errors from certidude.auth import login_required, login_optional, authorize_admin from certidude.decorators import csrf_protection, MyEncoder -from certidude.firewall import whitelist_subnets, whitelist_content_types from datetime import datetime from oscrypto import asymmetric from oscrypto.errors import SignatureError from xattr import getxattr from .utils import AuthorityHandler +from .utils.firewall import whitelist_subnets, whitelist_content_types logger = logging.getLogger(__name__) diff --git a/certidude/api/revoked.py b/certidude/api/revoked.py index fc6f448..44cb721 100644 --- a/certidude/api/revoked.py +++ b/certidude/api/revoked.py @@ -1,8 +1,8 @@ import falcon import logging from certidude import const, config -from certidude.firewall import whitelist_subnets from .utils import AuthorityHandler +from .utils.firewall import whitelist_subnets logger = logging.getLogger(__name__) diff --git a/certidude/api/scep.py b/certidude/api/scep.py index 2c0f59c..dee63ba 100644 --- a/certidude/api/scep.py +++ b/certidude/api/scep.py @@ -4,10 +4,10 @@ from asn1crypto import cms, algos from asn1crypto.core import SetOf, PrintableString from base64 import b64decode from certidude import config -from certidude.firewall import whitelist_subnets from oscrypto import keys, asymmetric, symmetric from oscrypto.errors import SignatureError from .utils import AuthorityHandler +from .utils.firewall import whitelist_subnets # Monkey patch asn1crypto diff --git a/certidude/api/script.py b/certidude/api/script.py index dd2066d..db3f4bf 100644 --- a/certidude/api/script.py +++ b/certidude/api/script.py @@ -2,8 +2,8 @@ import logging import os from certidude import const, config from jinja2 import Environment, FileSystemLoader -from certidude.firewall import whitelist_subject from .utils import AuthorityHandler +from .utils.firewall import whitelist_subject logger = logging.getLogger(__name__) env = Environment(loader=FileSystemLoader(config.SCRIPT_DIR), trim_blocks=True) diff --git a/certidude/api/utils.py b/certidude/api/utils/__init__.py similarity index 100% rename from certidude/api/utils.py rename to certidude/api/utils/__init__.py diff --git a/certidude/firewall.py b/certidude/api/utils/firewall.py similarity index 100% rename from certidude/firewall.py rename to certidude/api/utils/firewall.py diff --git a/certidude/auth.py b/certidude/auth.py index e57208d..e0abc4e 100644 --- a/certidude/auth.py +++ b/certidude/auth.py @@ -9,7 +9,6 @@ import re import socket from base64 import b64decode from certidude.user import User -from certidude.firewall import whitelist_subnets from certidude import config, const logger = logging.getLogger("api") From 7b6175ab372dcee0e3ff5aff6257619350a4574f Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 14:33:45 +0200 Subject: [PATCH 28/30] api.utils.firewall: Drop click usage and remove unneeded imports --- certidude/api/utils/firewall.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/certidude/api/utils/firewall.py b/certidude/api/utils/firewall.py index 6a16d49..d714b68 100644 --- a/certidude/api/utils/firewall.py +++ b/certidude/api/utils/firewall.py @@ -1,7 +1,6 @@ import falcon import logging -import click from asn1crypto import pem, x509 logger = logging.getLogger("api") @@ -10,8 +9,6 @@ def whitelist_subnets(subnets): """ Validate source IP address of API call against subnet list """ - import falcon - def wrapper(func): def wrapped(self, req, resp, *args, **kwargs): # Check for administration subnet whitelist @@ -30,8 +27,6 @@ def whitelist_subnets(subnets): return wrapper def whitelist_content_types(*content_types): - import falcon - def wrapper(func): def wrapped(self, req, resp, *args, **kwargs): for content_type in content_types: @@ -58,7 +53,7 @@ def whitelist_subject(func): header, _, der_bytes = pem.unarmor(buf.replace("\t", "").encode("ascii")) origin_cert = x509.Certificate.load(der_bytes) if origin_cert.native == cert.native: - click.echo("Subject authenticated using certificates") + logger.debug("Subject authenticated using certificates") return func(self, req, resp, cn, *args, **kwargs) # For backwards compatibility check source IP address @@ -73,4 +68,3 @@ def whitelist_subject(func): else: return func(self, req, resp, cn, *args, **kwargs) return wrapped - From 61de8617025934fc4ec7b9aef0ec8aa8bcbd7c70 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 14:39:06 +0200 Subject: [PATCH 29/30] travis: Use suggested syntax for caching pip data --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2fe05f9..74d359b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,4 @@ script: - sudo coverage combine - sudo coverage report - sudo coverage xml -i -cache: - directories: - - $HOME/.cache/pip +cache: pip From 5519f63c0c543a6467c38d85ebf448cfdd8c9bb4 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Sat, 3 Feb 2018 14:46:55 +0200 Subject: [PATCH 30/30] travis: Use sudo -H when calling pip --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 74d359b..cd1593c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,9 @@ script: - sudo apt install software-properties-common python3-setuptools python3-mysql.connector python3-pyxattr - sudo mkdir -p /etc/systemd/system # Until Travis is stuck with 14.04 - sudo easy_install3 pip - - sudo pip3 install -r requirements.txt - - sudo pip3 install codecov pytest-cov requests-kerberos - - sudo pip3 install -e . + - sudo -H pip3 install -r requirements.txt + - sudo -H pip3 install codecov pytest-cov requests-kerberos + - sudo -H pip3 install -e . - echo ca | sudo tee /etc/hostname - echo 127.0.0.1 localhost | sudo tee /etc/hosts - echo 127.0.1.1 ca.example.lan ca | sudo tee -a /etc/hosts