mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +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