mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-31 01:19:11 +00:00 
			
		
		
		
	Add preliminary Python 2.x support
This commit is contained in:
		| @@ -123,18 +123,19 @@ def certidude_app(): | ||||
|                 message = record.msg % record.args, | ||||
|                 severity = record.levelname.lower())) | ||||
|  | ||||
|     sql_handler = MySQLLogHandler(config.DATABASE_POOL) | ||||
|     if config.DATABASE_POOL: | ||||
|         sql_handler = MySQLLogHandler(config.DATABASE_POOL) | ||||
|     push_handler = PushLogHandler() | ||||
|  | ||||
|     for facility in "api", "cli": | ||||
|         logger = logging.getLogger(facility) | ||||
|         logger.setLevel(logging.DEBUG) | ||||
|         logger.addHandler(sql_handler) | ||||
|         if config.DATABASE_POOL: | ||||
|             logger.addHandler(sql_handler) | ||||
|         logger.addHandler(push_handler) | ||||
|  | ||||
|  | ||||
|     logging.getLogger("cli").debug("Started Certidude at %s", | ||||
|         socket.getaddrinfo(socket.gethostname(), 0, flags=socket.AI_CANONNAME)[0][3]) | ||||
|     logging.getLogger("cli").debug("Started Certidude at %s", config.FQDN) | ||||
|  | ||||
|     import atexit | ||||
|  | ||||
|   | ||||
| @@ -22,7 +22,7 @@ class RequestListResource(object): | ||||
|         Submit certificate signing request (CSR) in PEM format | ||||
|         """ | ||||
|         # Parse remote IPv4/IPv6 address | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"]) | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"].decode("utf-8")) | ||||
|  | ||||
|         # Check for CSR submission whitelist | ||||
|         if config.REQUEST_SUBNETS: | ||||
| @@ -30,7 +30,7 @@ class RequestListResource(object): | ||||
|                 if subnet.overlaps(remote_addr): | ||||
|                     break | ||||
|             else: | ||||
|                logger.warning("Attempted to submit signing request from non-whitelisted address %s", req.env["REMOTE_ADDR"]) | ||||
|                logger.warning("Attempted to submit signing request from non-whitelisted address %s", remote_addr) | ||||
|                raise falcon.HTTPForbidden("Forbidden", "IP address %s not whitelisted" % remote_addr) | ||||
|  | ||||
|         if req.get_header("Content-Type") != "application/pkcs10": | ||||
|   | ||||
| @@ -18,7 +18,7 @@ logger = logging.getLogger("api") | ||||
| # address eg via LDAP, hence to keep things simple | ||||
| # we simply use Kerberos to authenticate. | ||||
|  | ||||
| FQDN = socket.getaddrinfo(socket.gethostname(), 0, flags=socket.AI_CANONNAME)[0][3] | ||||
| FQDN = socket.getaddrinfo(socket.gethostname(), 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] | ||||
|  | ||||
| if not os.getenv("KRB5_KTNAME"): | ||||
|     click.echo("Kerberos keytab not specified, set environment variable 'KRB5_KTNAME'", err=True) | ||||
| @@ -89,7 +89,7 @@ def authorize_admin(func): | ||||
|     def wrapped(self, req, resp, *args, **kwargs): | ||||
|         from certidude import config | ||||
|         # Parse remote IPv4/IPv6 address | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"]) | ||||
|         remote_addr = ipaddress.ip_network(req.env["REMOTE_ADDR"].decode("utf-8")) | ||||
|  | ||||
|         # Check for administration subnet whitelist | ||||
|         print("Comparing:", config.ADMIN_SUBNETS, "To:", remote_addr) | ||||
| @@ -97,12 +97,12 @@ def authorize_admin(func): | ||||
|             if subnet.overlaps(remote_addr): | ||||
|                 break | ||||
|         else: | ||||
|             logger.info("Rejected access to administrative call %s by %s from %s, source address not whitelisted", req.env["PATH_INFO"], req.context["user"], req.env["REMOTE_ADDR"]) | ||||
|             logger.info("Rejected access to administrative call %s by %s from %s, source address not whitelisted", req.env["PATH_INFO"], req.context["user"], remote_addr) | ||||
|             raise falcon.HTTPForbidden("Forbidden", "Remote address %s not whitelisted" % remote_addr) | ||||
|  | ||||
|         # Check for username whitelist | ||||
|         if req.context.get("user") not in config.ADMIN_USERS: | ||||
|             logger.info("Rejected access to administrative call %s by %s from %s, user not whitelisted", req.env["PATH_INFO"], req.context["user"], req.env["REMOTE_ADDR"]) | ||||
|             logger.info("Rejected access to administrative call %s by %s from %s, user not whitelisted", req.env["PATH_INFO"], req.context["user"], remote_addr) | ||||
|             raise falcon.HTTPForbidden("Forbidden", "User %s not whitelisted" % req.context.get("user")) | ||||
|  | ||||
|         # Retain username, TODO: Better abstraction with username, e-mail, sn, gn? | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import click | ||||
| import os | ||||
| import re | ||||
| import socket | ||||
| import urllib.request | ||||
| import requests | ||||
| from OpenSSL import crypto | ||||
| from certidude import config, push | ||||
| from certidude.wrappers import Certificate, Request | ||||
| @@ -24,12 +24,9 @@ def publish_certificate(func): | ||||
|  | ||||
|         if config.PUSH_PUBLISH: | ||||
|             url = config.PUSH_PUBLISH % csr.fingerprint() | ||||
|             notification = urllib.request.Request(url, cert.dump().encode("ascii")) | ||||
|             notification.add_header("User-Agent", "Certidude API") | ||||
|             notification.add_header("Content-Type", "application/x-x509-user-cert") | ||||
|             click.echo("Publishing certificate at %s, waiting for response..." % url) | ||||
|             response = urllib.request.urlopen(notification) | ||||
|             response.read() | ||||
|             click.echo("Publishing certificate at %s ..." % url) | ||||
|             requests.post(url, data=cert.dump(), | ||||
|                 headers={"User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert"}) | ||||
|             push.publish("request-signed", csr.common_name) | ||||
|         return cert | ||||
|     return wrapped | ||||
| @@ -146,22 +143,8 @@ def delete_request(common_name): | ||||
|     push.publish("request-deleted", request_sha1sum) | ||||
|  | ||||
|     # Write empty certificate to long-polling URL | ||||
|     url = config.PUSH_PUBLISH % request_sha1sum | ||||
|     click.echo("POST-ing empty certificate at %s, waiting for response..." % url) | ||||
|     publisher = urllib.request.Request(url, b"-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n") | ||||
|     publisher.add_header("User-Agent", "Certidude API") | ||||
|  | ||||
|     try: | ||||
|         response = urllib.request.urlopen(publisher) | ||||
|         body = response.read() | ||||
|     except urllib.error.HTTPError as err: | ||||
|         if err.code == 404: | ||||
|             print("No subscribers on the channel") | ||||
|         else: | ||||
|             raise | ||||
|     else: | ||||
|         print("Push server returned:", response.code, body) | ||||
|  | ||||
|     requests.delete(config.PUSH_PUBLISH % request_sha1sum, | ||||
|         headers={"User-Agent": "Certidude API"}) | ||||
|  | ||||
| @publish_certificate | ||||
| def sign(req, overwrite=False, delete=True): | ||||
|   | ||||
| @@ -23,7 +23,8 @@ from jinja2 import Environment, PackageLoader | ||||
| from time import sleep | ||||
| from setproctitle import setproctitle | ||||
| from OpenSSL import crypto | ||||
|  | ||||
| from future.standard_library import install_aliases | ||||
| install_aliases() | ||||
|  | ||||
| env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) | ||||
|  | ||||
| @@ -44,7 +45,7 @@ assert hasattr(crypto.X509Req(), "get_extensions"), "You're running too old vers | ||||
|  | ||||
| # Parse command-line argument defaults from environment | ||||
| HOSTNAME = socket.gethostname() | ||||
| FQDN = socket.getaddrinfo(HOSTNAME, 0, flags=socket.AI_CANONNAME)[0][3] | ||||
| FQDN = socket.getaddrinfo(HOSTNAME, 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] | ||||
| USERNAME = os.environ.get("USER") | ||||
| NOW = datetime.utcnow().replace(tzinfo=None) | ||||
| FIRST_NAME = None | ||||
| @@ -66,9 +67,8 @@ if os.getuid() >= 1000: | ||||
| @click.option("-f", "--fork", default=False, is_flag=True, help="Fork to background") | ||||
| def certidude_request_spawn(fork): | ||||
|     from certidude.helpers import certidude_request_certificate | ||||
|     from configparser import ConfigParser | ||||
|  | ||||
|     clients = ConfigParser() | ||||
|     clients = configparser.ConfigParser() | ||||
|     clients.readfp(open("/etc/certidude/client.conf")) | ||||
|  | ||||
|     services = ConfigParser() | ||||
|   | ||||
| @@ -1,14 +1,18 @@ | ||||
|  | ||||
| import click | ||||
| import codecs | ||||
| import configparser | ||||
| import ipaddress | ||||
| import os | ||||
| import socket | ||||
| import string | ||||
| from random import choice | ||||
| from urllib.parse import urlparse | ||||
|  | ||||
| FQDN = socket.getaddrinfo(socket.gethostname(), 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] | ||||
|  | ||||
| cp = configparser.ConfigParser() | ||||
| cp.read("/etc/certidude/server.conf") | ||||
| cp.readfp(codecs.open("/etc/certidude/server.conf", "r", "utf8")) | ||||
|  | ||||
| ADMIN_USERS = set([j for j in  cp.get("authorization", "admin_users").split(" ") if j]) | ||||
| ADMIN_SUBNETS = set([ipaddress.ip_network(j) for j in cp.get("authorization", "admin_subnets").split(" ") if j]) | ||||
| @@ -43,14 +47,16 @@ try: | ||||
|     PUSH_LONG_POLL = cp.get("push", "long_poll") | ||||
|     PUSH_PUBLISH = cp.get("push", "publish") | ||||
| except configparser.NoOptionError: | ||||
|     PUSH_SERVER = cp.get("push", "server") | ||||
|     PUSH_SERVER = cp.get("push", "server") or "http://localhost" | ||||
|     PUSH_EVENT_SOURCE = PUSH_SERVER + "/ev/%s" | ||||
|     PUSH_LONG_POLL = PUSH_SERVER + "/lp/%s" | ||||
|     PUSH_PUBLISH = PUSH_SERVER + "/pub?id=%s" | ||||
|  | ||||
| from urllib.parse import urlparse | ||||
| o = urlparse(cp.get("authority", "database")) | ||||
| if o.scheme == "mysql": | ||||
| o = urlparse(cp.get("authority", "database") if cp.has_option("authority", "database") else "") | ||||
|  | ||||
| if not o.scheme: | ||||
|     DATABASE_POOL = None | ||||
| elif o.scheme == "mysql": | ||||
|     import mysql.connector | ||||
|     DATABASE_POOL = mysql.connector.pooling.MySQLConnectionPool( | ||||
|         pool_size = 32, | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| # encoding: utf-8 | ||||
|  | ||||
| import falcon | ||||
| import ipaddress | ||||
| @@ -41,8 +42,6 @@ class MyEncoder(json.JSONEncoder): | ||||
|             return obj.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z" | ||||
|         if isinstance(obj, date): | ||||
|             return obj.strftime("%Y-%m-%d") | ||||
|         if isinstance(obj, map): | ||||
|             return tuple(obj) | ||||
|         if isinstance(obj, types.GeneratorType): | ||||
|             return tuple(obj) | ||||
|         if isinstance(obj, Request): | ||||
|   | ||||
| @@ -2,7 +2,6 @@ | ||||
| import click | ||||
| import os | ||||
| import requests | ||||
| import urllib.request | ||||
| from certidude import errors | ||||
| from certidude.wrappers import Certificate, Request | ||||
| from OpenSSL import crypto | ||||
| @@ -123,12 +122,11 @@ def certidude_request_certificate(url, key_path, request_path, certificate_path, | ||||
|         return | ||||
|     if submission.status_code == requests.codes.conflict: | ||||
|         raise errors.DuplicateCommonNameError("Different signing request with same CN is already present on server, server refuses to overwrite") | ||||
|     else: | ||||
|         submission.raise_for_status() | ||||
|  | ||||
|     if submission.text == '-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n': | ||||
|     elif submission.status_code == requests.codes.gone: | ||||
|         # Should the client retry or disable request submission? | ||||
|         raise ValueError("Server refused to sign the request") # TODO: Raise proper exception | ||||
|     else: | ||||
|         submission.raise_for_status() | ||||
|  | ||||
|     try: | ||||
|         cert = crypto.load_certificate(crypto.FILETYPE_PEM, submission.text) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
|  | ||||
| import click | ||||
| import json | ||||
| import urllib.request | ||||
| import requests | ||||
| from certidude import config | ||||
|  | ||||
|  | ||||
| @@ -13,25 +13,9 @@ def publish(event_type, event_data): | ||||
|         from certidude.decorators import MyEncoder | ||||
|         event_data = json.dumps(event_data, cls=MyEncoder) | ||||
|  | ||||
|     url = config.PUSH_PUBLISH % config.PUSH_TOKEN | ||||
|     click.echo("Posting event %s %s at %s, waiting for response..." % (repr(event_type), repr(event_data), repr(url))) | ||||
|     notification = urllib.request.Request( | ||||
|         url, | ||||
|         event_data.encode("utf-8"), | ||||
|         {"X-EventSource-Event":event_type.encode("ascii")}) | ||||
|     notification.add_header("User-Agent", "Certidude API") | ||||
|  | ||||
|     try: | ||||
|         response = urllib.request.urlopen(notification) | ||||
|         body = response.read() | ||||
|     except urllib.error.HTTPError as err: | ||||
|         if err.code == 404: | ||||
|             print("No subscribers on the channel") | ||||
|         else: | ||||
|             print("Failed to submit event, %s" % err) | ||||
|     else: | ||||
|         print("Push server returned:", response.code, body) | ||||
|         response.close() | ||||
|  | ||||
|     notification = requests.post( | ||||
|         config.PUSH_PUBLISH % config.PUSH_TOKEN, | ||||
|         data=event_data, | ||||
|         headers={"X-EventSource-Event": event_type, "User-Agent": "Certidude API"}) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -199,7 +199,7 @@ class Request(CertificateBase): | ||||
|         self.path = NotImplemented | ||||
|         self.created = NotImplemented | ||||
|  | ||||
|         if isinstance(mixed, io.TextIOWrapper): | ||||
|         if isinstance(mixed, file): | ||||
|             self.path = mixed.name | ||||
|             _, _, _, _, _, _, _, _, mtime, _ = os.stat(self.path) | ||||
|             self.created = datetime.fromtimestamp(mtime) | ||||
| @@ -248,7 +248,7 @@ class Certificate(CertificateBase): | ||||
|         self.path = NotImplemented | ||||
|         self.changed = NotImplemented | ||||
|  | ||||
|         if isinstance(mixed, io.TextIOWrapper): | ||||
|         if isinstance(mixed, file): | ||||
|             self.path = mixed.name | ||||
|             _, _, _, _, _, _, _, _, mtime, _ = os.stat(self.path) | ||||
|             self.changed = datetime.fromtimestamp(mtime) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user