From b0683b268d110afa1140194b19fd9e90cff956bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20V=C3=B5sandi?= Date: Mon, 1 May 2017 16:20:50 +0000 Subject: [PATCH] Attempt to run client as part of unittests --- .travis.yml | 14 +-- certidude/api/lease.py | 1 - certidude/cli.py | 149 ++++++++++++++----------- certidude/common.py | 3 +- certidude/config.py | 2 +- certidude/const.py | 19 ++-- certidude/helpers.py | 14 +-- certidude/templates/server/server.conf | 2 +- requirements.txt | 5 - setup.py | 7 +- tests/test_cli.py | 78 +++++++++++-- 11 files changed, 178 insertions(+), 116 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3029f2..7f39e90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ virtualenv: system_site_packages: true install: - pip install -r requirements.txt + - pip install codecov pytest-cov - pip install --editable . - - pip install codecov pytest-cov click ipaddress humanize falcon simplepam script: - sudo useradd adminbot -G sudo -p '$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1' - sudo useradd userbot -G users -p '$1$PBkf5waA$n9EV6WJ7PS6lyGWkgeTPf1' @@ -20,12 +20,12 @@ cache: directories: - $HOME/.cache/pip addons: + hostname: ca + hosts: + - ca.example.lan + - vpn.example.lan + - ipsec.example.lan apt: packages: - - python-xattr - - python-setproctitle - - python-markdown - - python-jinja2 + - python-click - python-configparser - - python-pyasn1 - - python-openssl diff --git a/certidude/api/lease.py b/certidude/api/lease.py index 82b48ec..18655e7 100644 --- a/certidude/api/lease.py +++ b/certidude/api/lease.py @@ -4,7 +4,6 @@ import falcon import logging import xattr from datetime import datetime -from pyasn1.codec.der import decoder from certidude import config, authority, push from certidude.auth import login_required, authorize_admin from certidude.decorators import serialize diff --git a/certidude/cli.py b/certidude/cli.py index cc34b8d..72dd90f 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -16,18 +16,10 @@ import sys from configparser import ConfigParser, NoOptionError, NoSectionError from certidude.helpers import certidude_request_certificate from certidude.common import expand_paths, ip_address, ip_network, apt, rpm, pip -from cryptography import x509 -from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import rsa from datetime import datetime, timedelta -from jinja2 import Environment, PackageLoader import const logger = logging.getLogger(__name__) -env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) # http://www.mad-hacking.net/documentation/linux/security/ssl-tls/creating-ca.xml # https://kjur.github.io/jsrsasign/ @@ -41,8 +33,13 @@ NOW = datetime.utcnow().replace(tzinfo=None) @click.command("request", help="Run processes for requesting certificates and configuring services") @click.option("-r", "--renew", default=False, is_flag=True, help="Renew now") @click.option("-f", "--fork", default=False, is_flag=True, help="Fork to background") -def certidude_request(fork, renew): +@click.option("-nw", "--no-wait", default=False, is_flag=True, help="Return immideately if server doesn't autosign") +def certidude_request(fork, renew, no_wait): + rpm("openssl") + apt("openssl") import requests + from jinja2 import Environment, PackageLoader + env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) if not os.path.exists(const.CLIENT_CONFIG_PATH): click.echo("No %s!" % const.CLIENT_CONFIG_PATH) @@ -59,12 +56,10 @@ def certidude_request(fork, renew): service_config.readfp(open(const.SERVICES_CONFIG_PATH)) # Process directories - run_dir = "/run/certidude" + if not os.path.exists(const.RUN_DIR): + click.echo("Creating: %s" % const.RUN_DIR) + os.makedirs(const.RUN_DIR) - # Prepare signer PID-s directory - if not os.path.exists(run_dir): - click.echo("Creating: %s" % run_dir) - os.makedirs(run_dir) context = globals() context.update(locals()) @@ -82,7 +77,7 @@ def certidude_request(fork, renew): try: endpoint_dhparam = clients.get(authority, "dhparam path") if not os.path.exists(endpoint_dhparam): - cmd = "openssl", "dhparam", "-out", endpoint_dhparam, "2048" + cmd = "openssl", "dhparam", "-out", endpoint_dhparam, ("512" if os.getenv("TRAVIS") else "2048") subprocess.check_call(cmd) except NoOptionError: pass @@ -125,7 +120,7 @@ def certidude_request(fork, renew): elif clients.get(authority, "trigger") != "interface up": continue - pid_path = os.path.join(run_dir, authority + ".pid") + pid_path = os.path.join(const.RUN_DIR, authority + ".pid") try: with open(pid_path) as fh: @@ -163,7 +158,7 @@ def certidude_request(fork, renew): endpoint_common_name, insecure=endpoint_insecure, autosign=True, - wait=True, + wait=not no_wait, renew=renew) break except requests.exceptions.Timeout: @@ -337,6 +332,7 @@ def certidude_request(fork, renew): @click.command("server", help="Set up OpenVPN server") @click.argument("authority") +@click.option("--common-name", "-cn", default=const.FQDN, help="Common name, %s by default" % const.FQDN) @click.option("--subnet", "-s", default="192.168.33.0/24", type=ip_network, help="OpenVPN subnet, 192.168.33.0/24 by default") @click.option("--local", "-l", default="0.0.0.0", help="OpenVPN listening address, defaults to all interfaces") @click.option("--port", "-p", default=1194, type=click.IntRange(1,60000), help="OpenVPN listening port, 1194 by default") @@ -346,7 +342,7 @@ def certidude_request(fork, renew): default="/etc/openvpn/site-to-client.conf", type=click.File(mode="w", atomic=True, lazy=True), help="OpenVPN configuration file") -def certidude_setup_openvpn_server(authority, config, subnet, route, local, proto, port): +def certidude_setup_openvpn_server(authority, common_name, config, subnet, route, local, proto, port): # Install dependencies apt("openvpn") rpm("openvpn") @@ -358,11 +354,13 @@ def certidude_setup_openvpn_server(authority, config, subnet, route, local, prot if client_config.has_section(authority): click.echo("Section '%s' already exists in %s, remove to regenerate" % (authority, const.CLIENT_CONFIG_PATH)) else: + client_config.add_section(authority) client_config.set(authority, "trigger", "interface up") - client_config.set(authority, "common name", const.HOSTNAME) - client_config.set(authority, "request path", "/etc/openvpn/keys/%s.csr" % const.HOSTNAME) - client_config.set(authority, "key path", "/etc/openvpn/keys/%s.key" % const.HOSTNAME) - client_config.set(authority, "certificate path", "/etc/openvpn/keys/%s.crt" % const.HOSTNAME) + client_config.set(authority, "common name", common_name) + slug = common_name.replace(".", "-") + client_config.set(authority, "request path", "/etc/openvpn/keys/%s.csr" % slug) + client_config.set(authority, "key path", "/etc/openvpn/keys/%s.key" % slug) + client_config.set(authority, "certificate path", "/etc/openvpn/keys/%s.crt" % slug) client_config.set(authority, "authority path", "/etc/openvpn/keys/ca.crt") client_config.set(authority, "revocations path", "/etc/openvpn/keys/ca.crl") client_config.set(authority, "dhparam path", "/etc/openvpn/keys/dhparam.pem") @@ -373,7 +371,7 @@ def certidude_setup_openvpn_server(authority, config, subnet, route, local, prot # Create corresponding section in /etc/certidude/services.conf - endpoint = "OpenVPN server %s of %s" % (const.FQDN, authority) + endpoint = "OpenVPN server %s of %s" % (common_name, authority) service_config = ConfigParser() if os.path.exists(const.SERVICES_CONFIG_PATH): service_config.readfp(open(const.SERVICES_CONFIG_PATH)) @@ -487,12 +485,13 @@ def certidude_setup_nginx(authority, site_config, tls_config, common_name, direc @click.command("client", help="Set up OpenVPN client") @click.argument("authority") @click.argument("remote") +@click.option("--common-name", "-cn", default=const.HOSTNAME, help="Common name, %s by default" % const.HOSTNAME) @click.option('--proto', "-t", default="udp", type=click.Choice(['udp', 'tcp']), help="OpenVPN transport protocol, UDP by default") @click.option("--config", "-o", default="/etc/openvpn/client-to-site.conf", type=click.File(mode="w", atomic=True, lazy=True), help="OpenVPN configuration file") -def certidude_setup_openvpn_client(authority, remote, config, proto): +def certidude_setup_openvpn_client(authority, remote, common_name, config, proto): # Install dependencies apt("openvpn") rpm("openvpn") @@ -506,10 +505,10 @@ def certidude_setup_openvpn_client(authority, remote, config, proto): else: client_config.add_section(authority) client_config.set(authority, "trigger", "interface up") - client_config.set(authority, "common name", const.HOSTNAME) - client_config.set(authority, "request path", "/etc/openvpn/keys/%s.csr" % const.HOSTNAME) - client_config.set(authority, "key path", "/etc/openvpn/keys/%s.key" % const.HOSTNAME) - client_config.set(authority, "certificate path", "/etc/openvpn/keys/%s.crt" % const.HOSTNAME) + client_config.set(authority, "common name", common_name) + client_config.set(authority, "request path", "/etc/openvpn/keys/%s.csr" % const.common_name) + client_config.set(authority, "key path", "/etc/openvpn/keys/%s.key" % common_name) + client_config.set(authority, "certificate path", "/etc/openvpn/keys/%s.crt" % common_name) client_config.set(authority, "authority path", "/etc/openvpn/keys/ca.crt") client_config.set(authority, "revocations path", "/etc/openvpn/keys/ca.crl") with open(const.CLIENT_CONFIG_PATH + ".part", 'wb') as fh: @@ -549,8 +548,8 @@ def certidude_setup_openvpn_client(authority, remote, config, proto): config.write("group nogroup\n") config.write("persist-tun\n") config.write("persist-key\n") - config.write("up /etc/openvpn/update-resolv-conf") - config.write("down /etc/openvpn/update-resolv-conf") + config.write("up /etc/openvpn/update-resolv-conf\n") + config.write("down /etc/openvpn/update-resolv-conf\n") click.echo("Generated %s" % config.name) click.echo("Inspect generated files and issue following to request certificate:") @@ -791,10 +790,21 @@ def certidude_setup_openvpn_networkmanager(authority, remote): @click.option("--server-flags", is_flag=True, help="Add TLS Server and IKE Intermediate extended key usage flags") @click.option("--outbox", default="smtp://smtp.%s" % const.DOMAIN, help="SMTP server, smtp://smtp.%s by default" % const.DOMAIN) def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, state, locality, organization, organizational_unit, common_name, directory, authority_lifetime, push_server, outbox, server_flags): - # Install dependencies - apt("python-setproctitle python-openssl python-falcon python-humanize python-markdown python-xattr") - rpm("python-setproctitle pyOpenSSL python-falcon python-humanize python-markdown pyxattr") - pip("gssapi") + if "." not in common_name: + raise ValueError("No FQDN configured on this system!") + # Install only rarely changing stuff from OS package management + apt("python-setproctitle cython python-dev libkrb5-dev libldap2-dev libffi-dev libssl-dev") + apt("python-mimeparse python-markdown python-xattr python-jinja2 python-cffi python-openssl") + pip("gssapi falcon cryptography humanize ipaddress simplepam humanize requests") + + from cryptography import x509 + from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import rsa + from jinja2 import Environment, PackageLoader + env = Environment(loader=PackageLoader("certidude", "templates"), trim_blocks=True) # Generate secret for tokens token_secret = ''.join(random.choice(string.letters + string.digits + '!@#$%^&*()') for i in range(50)) @@ -961,17 +971,22 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, click.echo("Signing %s..." % cert.subject) - # Create authority directory with 750 permissions + # Create directories with 770 permissions os.umask(0o027) if not os.path.exists(directory): os.makedirs(directory) # Create subdirectories with 770 permissions os.umask(0o007) - for subdir in ("signed", "requests", "revoked", "expired"): + for subdir in ("signed", "requests", "revoked", "expired", "meta"): if not os.path.exists(os.path.join(directory, subdir)): os.mkdir(os.path.join(directory, subdir)) + # Create SQLite database file with correct permissions + os.umask(0o117) + with open(os.path.join(directory, "meta", "db.sqlite"), "wb") as fh: + pass + # Set permission bits to 640 os.umask(0o137) with open(ca_crt, "wb") as fh: @@ -1138,6 +1153,11 @@ def certidude_serve(port, listen, fork): # Fetch UID, GID of certidude user if os.getuid() == 0: + # Process directories + if not os.path.exists(const.RUN_DIR): + click.echo("Creating: %s" % const.RUN_DIR) + os.makedirs(const.RUN_DIR) + import pwd _, _, uid, gid, gecos, root, shell = pwd.getpwnam("certidude") restricted_groups = [] @@ -1211,7 +1231,6 @@ def certidude_serve(port, listen, fork): click.echo("Listening on %s:%d" % (listen, port)) app = certidude_app(log_handlers) - httpd = make_server(listen, port, app, ThreadingWSGIServer) @@ -1219,28 +1238,17 @@ def certidude_serve(port, listen, fork): Drop privileges """ - if os.getuid() == 0: - # Initialize LDAP service ticket - if os.path.exists("/etc/cron.hourly/certidude"): - os.system("/etc/cron.hourly/certidude") + # Initialize LDAP service ticket + if os.path.exists("/etc/cron.hourly/certidude"): + os.system("/etc/cron.hourly/certidude") - # Drop privileges - if config.AUTHENTICATION_BACKENDS == {"pam"}: - # PAM needs access to /etc/shadow - import grp - name, passwd, num, mem = grp.getgrnam("shadow") - click.echo("Adding current user to shadow group due to PAM authentication backend") - restricted_groups.append(num) - - os.setgroups(restricted_groups) - os.setgid(gid) - os.setuid(uid) - - click.echo("Switched to user %s (uid=%d, gid=%d); member of groups %s" % - ("certidude", os.getuid(), os.getgid(), ", ".join([str(j) for j in os.getgroups()]))) - - os.umask(0o007) + # PAM needs access to /etc/shadow + if config.AUTHENTICATION_BACKENDS == {"pam"}: + import grp + name, passwd, num, mem = grp.getgrnam("shadow") + click.echo("Adding current user to shadow group due to PAM authentication backend") + restricted_groups.append(num) if config.EVENT_SOURCE_PUBLISH: from certidude.push import EventSourceLogHandler @@ -1254,13 +1262,28 @@ def certidude_serve(port, listen, fork): j.addHandler(handler) - def exit_handler(): - logger.debug("Shutting down Certidude") - import atexit - atexit.register(exit_handler) - logger.debug("Started Certidude at %s", const.FQDN) - if not fork or not os.fork(): + pid = os.getpid() + with open(const.SERVER_PID_PATH, "w") as pidfile: + pidfile.write("%d\n" % pid) + + def exit_handler(): + logger.debug("Shutting down Certidude") + import atexit + atexit.register(exit_handler) + logger.debug("Started Certidude at %s", const.FQDN) + + + # Drop privileges + os.setgroups(restricted_groups) + os.setgid(gid) + os.setuid(uid) + + click.echo("Switched to user %s (uid=%d, gid=%d); member of groups %s" % + ("certidude", os.getuid(), os.getgid(), ", ".join([str(j) for j in os.getgroups()]))) + + os.umask(0o007) + httpd.serve_forever() diff --git a/certidude/common.py b/certidude/common.py index 32155f3..b4a6134 100644 --- a/certidude/common.py +++ b/certidude/common.py @@ -1,13 +1,14 @@ import os import click -import ipaddress import subprocess def ip_network(j): + import ipaddress return ipaddress.ip_network(unicode(j)) def ip_address(j): + import ipaddress return ipaddress.ip_address(unicode(j)) def expand_paths(): diff --git a/certidude/config.py b/certidude/config.py index ec8e424..b7dea21 100644 --- a/certidude/config.py +++ b/certidude/config.py @@ -71,7 +71,7 @@ EVENT_SOURCE_SUBSCRIBE = cp.get("push", "event source subscribe") LONG_POLL_PUBLISH = cp.get("push", "long poll publish") LONG_POLL_SUBSCRIBE = cp.get("push", "long poll subscribe") -if os.getenv("TRAVIS"): # TODO: include nginx setup in Travis +if const.DOMAIN == "example.lan": # TODO: include nginx setup in Travis EVENT_SOURCE_PUBLISH = "" LONG_POLL_PUBLISH = "" LONG_POLL_SUBSCRIBE = "//nonexistant/lp/sub/%s" diff --git a/certidude/const.py b/certidude/const.py index 0c653cf..7a1977f 100644 --- a/certidude/const.py +++ b/certidude/const.py @@ -4,26 +4,23 @@ import os import socket import sys +RUN_DIR = "/run/certidude" CONFIG_DIR = os.path.expanduser("~/.certidude") if os.getuid() else "/etc/certidude" CONFIG_PATH = os.path.join(CONFIG_DIR, "server.conf") CLIENT_CONFIG_PATH = os.path.join(CONFIG_DIR, "client.conf") SERVICES_CONFIG_PATH = os.path.join(CONFIG_DIR, "services.conf") +SERVER_PID_PATH = os.path.join(CONFIG_DIR if os.getuid() else RUN_DIR, "server.pid") SERVER_LOG_PATH = os.path.join(CONFIG_DIR, "server.log") if os.getuid() else "/var/log/certidude-server.log" SIGNER_SOCKET_PATH = os.path.join(CONFIG_DIR, "signer.sock") if os.getuid() else "/run/certidude/signer.sock" -SIGNER_PID_PATH = os.path.join(CONFIG_DIR, "signer.pid") if os.getuid() else "/run/certidude/signer.pid" +SIGNER_PID_PATH = os.path.join(CONFIG_DIR if os.getuid() else RUN_DIR, "signer.pid") SIGNER_LOG_PATH = os.path.join(CONFIG_DIR, "signer.log") if os.getuid() else "/var/log/certidude-signer.log" -# Work around the 'asn1 encoding routines:ASN1_mbstring_ncopy:string too long' -# issue within OpenSSL ASN1 parser while running on Travis -if os.getenv("TRAVIS"): - FQDN = "buildbot" -else: - try: - FQDN = socket.getaddrinfo(socket.gethostname(), 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] - except socket.gaierror: - click.echo("Failed to resolve fully qualified hostname of this machine, make sure hostname -f works") - sys.exit(254) +try: + FQDN = socket.getaddrinfo(socket.gethostname(), 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] +except socket.gaierror: + click.echo("Failed to resolve fully qualified hostname of this machine, make sure hostname -f works") + sys.exit(254) if "." in FQDN: HOSTNAME, DOMAIN = FQDN.split(".", 1) diff --git a/certidude/helpers.py b/certidude/helpers.py index a424e65..0aa69ed 100644 --- a/certidude/helpers.py +++ b/certidude/helpers.py @@ -6,15 +6,7 @@ import tempfile from base64 import b64encode from datetime import datetime, timedelta from certidude import errors, const -from cryptography import x509 -from cryptography.hazmat.primitives.asymmetric import rsa, padding -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.serialization import Encoding -from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, AuthorityInformationAccessOID from configparser import ConfigParser -from cryptography import x509 -from cryptography.hazmat.backends import default_backend def selinux_fixup(path): """ @@ -30,6 +22,12 @@ def certidude_request_certificate(server, system_keytab_required, key_path, requ Exchange CSR for certificate using Certidude HTTP API server """ import requests + from cryptography import x509 + from cryptography.hazmat.primitives.asymmetric import rsa, padding + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.serialization import Encoding + from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, AuthorityInformationAccessOID # Create directories for path in key_path, request_path, certificate_path, authority_path, revocations_path: diff --git a/certidude/templates/server/server.conf b/certidude/templates/server/server.conf index 302c2fd..55cbb03 100644 --- a/certidude/templates/server/server.conf +++ b/certidude/templates/server/server.conf @@ -58,7 +58,7 @@ autosign subnets = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 # Use SQLite backend backend = sql -database = sqlite://{{ directory }}/db.sqlite +database = sqlite://{{ directory }}/meta/db.sqlite [signature] # Server certificate is granted to certificate with diff --git a/requirements.txt b/requirements.txt index a753956..711c534 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,2 @@ click>=6.7 configparser>=3.5.0 -cryptography>=1.7.1 -Jinja2>=2.8 -pyasn1>=0.1.9 -requests>=2.12.4 -requests-kerberos>=0.7.0 diff --git a/setup.py b/setup.py index 45594db..3c2e37f 100644 --- a/setup.py +++ b/setup.py @@ -20,12 +20,7 @@ setup( # Include here only stuff required to run certidude client install_requires=[ "click", - "cryptography", - "configparser", - "jinja2", - "pyasn1", - "requests", - "requests-kerberos" + "configparser" ], scripts=[ "misc/certidude" diff --git a/tests/test_cli.py b/tests/test_cli.py index 9438259..ff10747 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,18 +1,9 @@ -import os -import requests import subprocess import pwd -from falcon import testing from click.testing import CliRunner from certidude.cli import entry_point as cli from datetime import datetime, timedelta -from cryptography import x509 -from cryptography.hazmat.primitives.asymmetric import rsa, padding -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.backends import default_backend -from cryptography.x509.oid import NameOID import pytest -from xattr import setxattr # pkill py && rm -Rfv ~/.certidude && TRAVIS=1 py.test tests @@ -21,9 +12,16 @@ runner = CliRunner() @pytest.fixture(scope='module') def client(): from certidude.api import certidude_app - return testing.TestClient(certidude_app()) + from falcon import testing + app = certidude_app() + return testing.TestClient(app) def generate_csr(cn=None): + from cryptography import x509 + from cryptography.hazmat.primitives.asymmetric import rsa, padding + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.backends import default_backend + from cryptography.x509.oid import NameOID key = rsa.generate_private_key( public_exponent=65537, key_size=1024, @@ -36,17 +34,50 @@ def generate_csr(cn=None): return buf def test_cli_setup_authority(): + import shutil + import os + if os.path.exists("/run/certidude/signer.pid"): + with open("/run/certidude/signer.pid") as fh: + try: + os.kill(int(fh.read()), 15) + except OSError: + pass + os.unlink("/run/certidude/signer.pid") + if os.path.exists("/run/certidude/server.pid"): + with open("/run/certidude/server.pid") as fh: + try: + os.kill(int(fh.read()), 15) + except OSError: + pass + os.unlink("/run/certidude/server.pid") + + if os.path.exists("/var/lib/certidude/ca.example.lan"): + shutil.rmtree("/var/lib/certidude/ca.example.lan") + if os.path.exists("/etc/certidude/server.conf"): + os.unlink("/etc/certidude/server.conf") + if os.path.exists("/etc/certidude/client.conf"): + os.unlink("/etc/certidude/client.conf") + + # Remove OpenVPN stuff + for filename in os.listdir("/etc/openvpn"): + if filename.endswith(".conf"): + os.unlink(os.path.join("/etc/openvpn", filename)) + if os.path.exists("/etc/openvpn/keys"): + shutil.rmtree("/etc/openvpn/keys") + + from certidude import const + result = runner.invoke(cli, ['setup', 'authority']) assert not result.exception - from certidude import const, config, authority + from certidude import config, authority assert authority.ca_cert.serial_number >= 0x100000000000000000000000000000000000000 assert authority.ca_cert.serial_number <= 0xfffffffffffffffffffffffffffffffffffffff assert authority.ca_cert.not_valid_before < datetime.now() assert authority.ca_cert.not_valid_after > datetime.now() + timedelta(days=7000) # Start server before any signing operations are performed - result = runner.invoke(cli, ['serve', '-f', '-p', '8080']) + result = runner.invoke(cli, ['serve', '-f']) assert not result.exception # Password is bot, users created by Travis @@ -186,6 +217,7 @@ def test_cli_setup_authority(): # Insert lease as if VPN gateway had submitted it path, _, _ = authority.get_signed("test2") + from xattr import setxattr setxattr(path, "user.lease.address", b"127.0.0.1") setxattr(path, "user.lease.last_seen", b"random") r = client().simulate_get("/api/signed/test2/attr/") @@ -303,3 +335,25 @@ def test_cli_setup_authority(): r2 = client().simulate_get("/api/token/", query_string=r.content) assert r2.status_code == 200 # token consumed by anyone on unknown device assert r2.headers.get('content-type') == "application/x-pkcs12" + + + result = runner.invoke(cli, ['setup', 'openvpn', 'server', "-cn", "vpn.example.lan", "ca.example.lan"]) + assert not result.exception + + result = runner.invoke(cli, ['setup', 'openvpn', 'client', "-cn", "roadwarrior1", "ca.example.lan", "vpn.example.lan"]) + assert not result.exception + + import os + if not os.path.exists("/etc/openvpn/keys"): + os.makedirs("/etc/openvpn/keys") + + with open("/etc/certidude/client.conf", "a") as fh: + fh.write("insecure = true\n") + + # pregen dhparam + result = runner.invoke(cli, ["request", "--no-wait"]) + assert not result.exception + result = runner.invoke(cli, ['sign', 'vpn.example.lan']) + assert not result.exception + result = runner.invoke(cli, ["request", "--no-wait"]) + assert not result.exception