예제 #1
0
    def issue(self, issuer, subject, subject_mail=None):
        # Expand variables
        subject_username = subject.name
        if not subject_mail:
            subject_mail = subject.mail

        # Generate token
        token = ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(32))
        token_created = datetime.utcnow()
        token_expires = token_created + config.TOKEN_LIFETIME

        self.sql_execute("token_issue.sql",
            token_created, token_expires, token,
            issuer.name if issuer else None,
            subject_username, subject_mail, "rw")

        # Token lifetime in local time, to select timezone: dpkg-reconfigure tzdata
        try:
            with open("/etc/timezone") as fh:
                token_timezone = fh.read().strip()
        except EnvironmentError:
            token_timezone = None

        router = sorted([j[0] for j in authority.list_signed(
                    common_name=config.SERVICE_ROUTERS)])[0]
        protocols = ",".join(config.SERVICE_PROTOCOLS)
        url = config.TOKEN_URL % locals()

        context = globals()
        context.update(locals())

        mailer.send("token.md", to=subject_mail, **context)
        return token
예제 #2
0
    def on_get(self, req, resp):

        return dict(
            user = dict(
                name=req.context.get("user").name,
                gn=req.context.get("user").given_name,
                sn=req.context.get("user").surname,
                mail=req.context.get("user").mail
            ),
            request_submission_allowed = sum( # Dirty hack!
                [req.context.get("remote_addr") in j
                    for j in config.REQUEST_SUBNETS]),
            authority = dict(
                user_certificate_enrollment=config.USER_CERTIFICATE_ENROLLMENT,
                user_mutliple_certificates=config.USER_MULTIPLE_CERTIFICATES,
                outbox = config.OUTBOX,
                certificate = authority.certificate,
                events = config.PUSH_EVENT_SOURCE % config.PUSH_TOKEN,
                requests=authority.list_requests(),
                signed=authority.list_signed(),
                revoked=authority.list_revoked(),
                admin_users = User.objects.filter_admins(),
                user_subnets = config.USER_SUBNETS,
                autosign_subnets = config.AUTOSIGN_SUBNETS,
                request_subnets = config.REQUEST_SUBNETS,
                admin_subnets=config.ADMIN_SUBNETS,
                signature = dict(
                    certificate_lifetime=config.CERTIFICATE_LIFETIME,
                    revocation_list_lifetime=config.REVOCATION_LIST_LIFETIME
                )
            ) if req.context.get("user").is_admin() else None,
            features=dict(
                tagging=config.TAGGING_BACKEND,
                leases=False, #config.LEASES_BACKEND,
                logging=config.LOGGING_BACKEND))
예제 #3
0
    def on_get(self, req, resp, profile, suggested_filename):
        router = [j[0] for j in authority.list_signed(
            common_name=config.cp2.get(profile, "router"))][0]
        subnets = set([ip_network(j) for j in config.cp2.get(profile, "subnets").replace(",", " ").split(" ")])
        model = config.cp2.get(profile, "model")
        build_script_path = config.cp2.get(profile, "command")
        overlay_path = config.cp2.get(profile, "overlay")
        site_script_path = config.cp2.get(profile, "script")
        suffix = config.cp2.get(profile, "filename")

        build = "/var/lib/certidude/builder/" + profile
        log_path = build + "/build.log"
        if not os.path.exists(build + "/overlay/etc/uci-defaults"):
            os.makedirs(build + "/overlay/etc/uci-defaults")
        os.system("rsync -av " + overlay_path + "/ " + build + "/overlay/")

        if site_script_path:
            template = Template(open(site_script_path).read())
            with open(build + "/overlay/etc/uci-defaults/99-site-config", "w") as fh:
                fh.write(template.render(authority_name=const.FQDN))

        proc = subprocess.Popen(("/bin/bash", build_script_path),
            stdout=open(log_path, "w"), stderr=subprocess.STDOUT,
            close_fds=True, shell=False,
            cwd=os.path.dirname(os.path.realpath(build_script_path)),
            env={"PROFILE": model, "PATH":"/usr/sbin:/usr/bin:/sbin:/bin",
                "ROUTER": router,
                "IKE": config.cp2.get(profile, "ike"),
                "ESP": config.cp2.get(profile, "esp"),
                "SUBNETS": ",".join(str(j) for j in subnets),
                "AUTHORITY_CERTIFICATE_ALGORITHM": authority.public_key.algorithm,
                "AUTHORITY_CERTIFICATE_DISTINGUISHED_NAME": cert_to_dn(authority.certificate),
                "BUILD":build, "OVERLAY":build + "/overlay/"},
            startupinfo=None, creationflags=0)
        proc.communicate()
        if proc.returncode:
            logger.info("Build script finished with non-zero exitcode, see %s for more information" % log_path)
            raise falcon.HTTPInternalServerError("Build script finished with non-zero exitcode")

        for dname in os.listdir(build):
            if dname.startswith("lede-imagebuilder-"):
                for root, dirs, files in os.walk(os.path.join(build, dname, "bin", "targets")):
                    for filename in files:
                        if filename.endswith(suffix):
                            path = os.path.join(root, filename)
                            click.echo("Serving: %s" % path)
                            resp.body = open(path, "rb").read()
                            resp.set_header("Content-Disposition", ("attachment; filename=%s" % suggested_filename))
                            return
        raise falcon.HTTPNotFound()
예제 #4
0
 def on_get(self, req, resp):
     return {"signed":authority.list_signed()}
예제 #5
0
    def on_get(self, req, resp):

        def serialize_requests(g):
            for common_name, path, buf, req, submitted, server in g():
                try:
                    submission_address = getxattr(path, "user.request.address").decode("ascii") # TODO: move to authority.py
                except IOError:
                    submission_address = None
                try:
                    submission_hostname = getxattr(path, "user.request.hostname").decode("ascii") # TODO: move to authority.py
                except IOError:
                    submission_hostname = None
                yield dict(
                    server = self.authority.server_flags(common_name),
                    submitted = submitted,
                    common_name = common_name,
                    address = submission_address,
                    hostname = submission_hostname if submission_hostname != submission_address else None,
                    md5sum = hashlib.md5(buf).hexdigest(),
                    sha1sum = hashlib.sha1(buf).hexdigest(),
                    sha256sum = hashlib.sha256(buf).hexdigest(),
                    sha512sum = hashlib.sha512(buf).hexdigest()
                )

        def serialize_revoked(g):
            for common_name, path, buf, cert, signed, expired, revoked, reason in g():
                yield dict(
                    serial = "%x" % cert.serial_number,
                    common_name = common_name,
                    # TODO: key type, key length, key exponent, key modulo
                    signed = signed,
                    expired = expired,
                    revoked = revoked,
                    reason = reason,
                    sha256sum = hashlib.sha256(buf).hexdigest())

        def serialize_certificates(g):
            for common_name, path, buf, cert, signed, expires in g():
                # Extract certificate tags from filesystem
                try:
                    tags = []
                    for tag in getxattr(path, "user.xdg.tags").decode("utf-8").split(","):
                        if "=" in tag:
                            k, v = tag.split("=", 1)
                        else:
                            k, v = "other", tag
                        tags.append(dict(id=tag, key=k, value=v))
                except IOError: # No such attribute(s)
                    tags = None

                attributes = {}
                for key in listxattr(path):
                    if key.startswith(b"user.machine."):
                        attributes[key[13:].decode("ascii")] = getxattr(path, key).decode("ascii")

                # Extract lease information from filesystem
                try:
                    last_seen = datetime.strptime(getxattr(path, "user.lease.last_seen").decode("ascii"), "%Y-%m-%dT%H:%M:%S.%fZ")
                    lease = dict(
                        inner_address = getxattr(path, "user.lease.inner_address").decode("ascii"),
                        outer_address = getxattr(path, "user.lease.outer_address").decode("ascii"),
                        last_seen = last_seen,
                        age = datetime.utcnow() - last_seen
                    )
                except IOError: # No such attribute(s)
                    lease = None

                try:
                    signer_username = getxattr(path, "user.signature.username").decode("ascii")
                except IOError:
                    signer_username = None

                # TODO: dedup
                yield dict(
                    serial = "%x" % cert.serial_number,
                    organizational_unit = cert.subject.native.get("organizational_unit_name"),
                    common_name = common_name,
                    # TODO: key type, key length, key exponent, key modulo
                    signed = signed,
                    expires = expires,
                    sha256sum = hashlib.sha256(buf).hexdigest(),
                    signer = signer_username,
                    lease = lease,
                    tags = tags,
                    attributes = attributes or None,
                    extensions = dict([
                        (e["extn_id"].native, e["extn_value"].native)
                        for e in cert["tbs_certificate"]["extensions"]
                        if e["extn_id"].native in ("extended_key_usage",)])
                )

        if req.context.get("user").is_admin():
            logger.info("Logged in authority administrator %s from %s" % (req.context.get("user"), req.context.get("remote_addr")))
        else:
            logger.info("Logged in authority user %s from %s" % (req.context.get("user"), req.context.get("remote_addr")))
        return dict(
            user = dict(
                name=req.context.get("user").name,
                gn=req.context.get("user").given_name,
                sn=req.context.get("user").surname,
                mail=req.context.get("user").mail
            ),
            request_submission_allowed = config.REQUEST_SUBMISSION_ALLOWED,
            service = dict(
                protocols = config.SERVICE_PROTOCOLS,
                routers = [j[0] for j in authority.list_signed(
                    common_name=config.SERVICE_ROUTERS)]
            ),
            authority = dict(
                builder = dict(
                    profiles = config.IMAGE_BUILDER_PROFILES
                ),
                tagging = [dict(name=t[0], type=t[1], title=t[2]) for t in config.TAG_TYPES],
                lease = dict(
                    offline = 600, # Seconds from last seen activity to consider lease offline, OpenVPN reneg-sec option
                    dead = 604800 # Seconds from last activity to consider lease dead, X509 chain broken or machine discarded
                ),
                certificate = dict(
                    algorithm = authority.public_key.algorithm,
                    common_name = self.authority.certificate.subject.native["common_name"],
                    distinguished_name = cert_to_dn(self.authority.certificate),
                    md5sum = hashlib.md5(self.authority.certificate_buf).hexdigest(),
                    blob = self.authority.certificate_buf.decode("ascii"),
                ),
                mailer = dict(
                    name = config.MAILER_NAME,
                    address = config.MAILER_ADDRESS
                ) if config.MAILER_ADDRESS else None,
                machine_enrollment_subnets=config.MACHINE_ENROLLMENT_SUBNETS,
                user_enrollment_allowed=config.USER_ENROLLMENT_ALLOWED,
                user_multiple_certificates=config.USER_MULTIPLE_CERTIFICATES,
                events = config.EVENT_SOURCE_SUBSCRIBE % config.EVENT_SOURCE_TOKEN,
                requests=serialize_requests(self.authority.list_requests),
                signed=serialize_certificates(self.authority.list_signed),
                revoked=serialize_revoked(self.authority.list_revoked),
                admin_users = User.objects.filter_admins(),
                user_subnets = config.USER_SUBNETS or None,
                autosign_subnets = config.AUTOSIGN_SUBNETS or None,
                request_subnets = config.REQUEST_SUBNETS or None,
                admin_subnets=config.ADMIN_SUBNETS or None,
                signature = dict(
                    revocation_list_lifetime=config.REVOCATION_LIST_LIFETIME,
                    profiles = sorted([p.serialize() for p in config.PROFILES.values()], key=lambda p:p.get("slug")),

                )
            ) if req.context.get("user").is_admin() else None,
            features=dict(
                ocsp=bool(config.OCSP_SUBNETS),
                crl=bool(config.CRL_SUBNETS),
                token=bool(config.TOKEN_URL),
                tagging=True,
                leases=True,
                logging=config.LOGGING_BACKEND))