mirror of
https://github.com/laurivosandi/certidude
synced 2025-10-30 08:59:13 +00:00
Move certidude.firewall to api.utils.firewall where it belongs
This commit is contained in:
@@ -4,9 +4,10 @@ import re
|
||||
from xattr import setxattr, listxattr, removexattr
|
||||
from certidude import push
|
||||
from certidude.decorators import serialize, csrf_protection
|
||||
from certidude.firewall import whitelist_subject
|
||||
from certidude.auth import login_required, authorize_admin
|
||||
|
||||
from .utils.firewall import whitelist_subject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AttributeResource(object):
|
||||
|
||||
@@ -5,10 +5,10 @@ from asn1crypto.util import timezone
|
||||
from asn1crypto import ocsp
|
||||
from base64 import b64decode
|
||||
from certidude import config
|
||||
from certidude.firewall import whitelist_subnets
|
||||
from datetime import datetime
|
||||
from oscrypto import asymmetric
|
||||
from .utils import AuthorityHandler
|
||||
from .utils.firewall import whitelist_subnets
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ from base64 import b64decode
|
||||
from certidude import config, push, errors
|
||||
from certidude.auth import login_required, login_optional, authorize_admin
|
||||
from certidude.decorators import csrf_protection, MyEncoder
|
||||
from certidude.firewall import whitelist_subnets, whitelist_content_types
|
||||
from datetime import datetime
|
||||
from oscrypto import asymmetric
|
||||
from oscrypto.errors import SignatureError
|
||||
from xattr import getxattr
|
||||
from .utils import AuthorityHandler
|
||||
from .utils.firewall import whitelist_subnets, whitelist_content_types
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import falcon
|
||||
import logging
|
||||
from certidude import const, config
|
||||
from certidude.firewall import whitelist_subnets
|
||||
from .utils import AuthorityHandler
|
||||
from .utils.firewall import whitelist_subnets
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ from asn1crypto import cms, algos
|
||||
from asn1crypto.core import SetOf, PrintableString
|
||||
from base64 import b64decode
|
||||
from certidude import config
|
||||
from certidude.firewall import whitelist_subnets
|
||||
from oscrypto import keys, asymmetric, symmetric
|
||||
from oscrypto.errors import SignatureError
|
||||
from .utils import AuthorityHandler
|
||||
from .utils.firewall import whitelist_subnets
|
||||
|
||||
# Monkey patch asn1crypto
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import logging
|
||||
import os
|
||||
from certidude import const, config
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from certidude.firewall import whitelist_subject
|
||||
from .utils import AuthorityHandler
|
||||
from .utils.firewall import whitelist_subject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
env = Environment(loader=FileSystemLoader(config.SCRIPT_DIR), trim_blocks=True)
|
||||
|
||||
76
certidude/api/utils/firewall.py
Normal file
76
certidude/api/utils/firewall.py
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
import falcon
|
||||
import logging
|
||||
import click
|
||||
from asn1crypto import pem, x509
|
||||
|
||||
logger = logging.getLogger("api")
|
||||
|
||||
def whitelist_subnets(subnets):
|
||||
"""
|
||||
Validate source IP address of API call against subnet list
|
||||
"""
|
||||
import falcon
|
||||
|
||||
def wrapper(func):
|
||||
def wrapped(self, req, resp, *args, **kwargs):
|
||||
# Check for administration subnet whitelist
|
||||
for subnet in subnets:
|
||||
if req.context.get("remote_addr") in subnet:
|
||||
break
|
||||
else:
|
||||
logger.info("Rejected access to administrative call %s by %s from %s, source address not whitelisted",
|
||||
req.env["PATH_INFO"],
|
||||
req.context.get("user", "unauthenticated user"),
|
||||
req.context.get("remote_addr"))
|
||||
raise falcon.HTTPForbidden("Forbidden", "Remote address %s not whitelisted" % req.context.get("remote_addr"))
|
||||
|
||||
return func(self, req, resp, *args, **kwargs)
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
||||
def whitelist_content_types(*content_types):
|
||||
import falcon
|
||||
|
||||
def wrapper(func):
|
||||
def wrapped(self, req, resp, *args, **kwargs):
|
||||
for content_type in content_types:
|
||||
if req.get_header("Content-Type") == content_type:
|
||||
return func(self, req, resp, *args, **kwargs)
|
||||
raise falcon.HTTPUnsupportedMediaType(
|
||||
"This API call accepts only %s content type" % ", ".join(content_types))
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
||||
def whitelist_subject(func):
|
||||
def wrapped(self, req, resp, cn, *args, **kwargs):
|
||||
from ipaddress import ip_address
|
||||
from certidude import authority
|
||||
from xattr import getxattr
|
||||
try:
|
||||
path, buf, cert, signed, expires = authority.get_signed(cn)
|
||||
except IOError:
|
||||
raise falcon.HTTPNotFound()
|
||||
else:
|
||||
# First attempt to authenticate client with certificate
|
||||
buf = req.get_header("X-SSL-CERT")
|
||||
if buf:
|
||||
header, _, der_bytes = pem.unarmor(buf.replace("\t", "").encode("ascii"))
|
||||
origin_cert = x509.Certificate.load(der_bytes)
|
||||
if origin_cert.native == cert.native:
|
||||
click.echo("Subject authenticated using certificates")
|
||||
return func(self, req, resp, cn, *args, **kwargs)
|
||||
|
||||
# For backwards compatibility check source IP address
|
||||
# TODO: make it disableable
|
||||
try:
|
||||
inner_address = getxattr(path, "user.lease.inner_address").decode("ascii")
|
||||
except IOError:
|
||||
raise falcon.HTTPForbidden("Forbidden", "Remote address %s not whitelisted" % req.context.get("remote_addr"))
|
||||
else:
|
||||
if req.context.get("remote_addr") != ip_address(inner_address):
|
||||
raise falcon.HTTPForbidden("Forbidden", "Remote address %s mismatch" % req.context.get("remote_addr"))
|
||||
else:
|
||||
return func(self, req, resp, cn, *args, **kwargs)
|
||||
return wrapped
|
||||
|
||||
Reference in New Issue
Block a user