mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-22 08:15:18 +00:00
Attempt to run client as part of unittests
This commit is contained in:
parent
cc4f13086e
commit
b0683b268d
14
.travis.yml
14
.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
|
||||
|
@ -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
|
||||
|
149
certidude/cli.py
149
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()
|
||||
|
||||
|
||||
|
@ -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():
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
7
setup.py
7
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"
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user