certidude/certidude/api/lease.py

61 lines
2.8 KiB
Python

import falcon
import logging
import os
import re
import xattr
from datetime import datetime
from certidude import config, push
from certidude.decorators import serialize
from .utils import AuthorityHandler
from .utils.firewall import login_required, authorize_admin, authorize_server
logger = logging.getLogger(__name__)
# TODO: lease namespacing (?)
class LeaseDetailResource(AuthorityHandler):
@serialize
@login_required
@authorize_admin
def on_get(self, req, resp, cn):
try:
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"),
outer_address = xattr.getxattr(path, "user.lease.outer_address").decode("ascii")
)
except EnvironmentError: # Certificate or attribute not found
raise falcon.HTTPNotFound()
class LeaseResource(AuthorityHandler):
@authorize_server
def on_post(self, req, resp):
client_common_name = req.get_param("client", required=True)
m = re.match("^(.*, )*CN=(.+?)(, .*)*$", client_common_name) # It's actually DN, resolve it to CN
if m:
_, client_common_name, _ = m.groups()
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"
xattr.setxattr(path, "user.lease.outer_address", req.get_param("outer_address", required=True).encode("ascii"))
xattr.setxattr(path, "user.lease.inner_address", req.get_param("inner_address", required=True).encode("ascii"))
xattr.setxattr(path, "user.lease.last_seen", now)
push.publish("lease-update", client_common_name)
server_common_name = req.context.get("machine")
path = os.path.join(config.SIGNED_DIR, server_common_name + ".pem")
xattr.setxattr(path, "user.lease.outer_address", "")
xattr.setxattr(path, "user.lease.inner_address", "%s" % req.context.get("remote_addr"))
xattr.setxattr(path, "user.lease.last_seen", now)
push.publish("lease-update", server_common_name)
# client-disconnect is pretty much unusable:
# - Android Connect Client results "IP packet with unknown IP version=2" on gateway
# - NetworkManager just kills OpenVPN client, disconnect is never reported
# - Disconnect is also not reported when uplink connection dies or laptop goes to sleep