From 3af5809d715fcfc5182e171385678483dd6f84c5 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 2 Jun 2017 12:41:03 +0200 Subject: [PATCH] Add option for CA certificate for validating clients This can be used to secure TCP traffic between Radicale and a reverse proxy --- config | 4 ++++ radicale/__init__.py | 7 +++++++ radicale/__main__.py | 6 +++++- radicale/config.py | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/config b/config index 958fb46..8f332e6 100644 --- a/config +++ b/config @@ -41,6 +41,10 @@ # SSL private key #key = /etc/ssl/radicale.key.pem +# CA certificate for validating clients. This can be used to secure +# TCP traffic between Radicale and a reverse proxy +#certificate_authority = + # SSL Protocol used. See python's ssl module for available values #protocol = PROTOCOL_TLSv1_2 diff --git a/radicale/__init__.py b/radicale/__init__.py index ec835ed..07c1533 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -143,6 +143,7 @@ class HTTPSServer(HTTPServer): key = None protocol = None ciphers = None + certificate_authority = None def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" @@ -150,6 +151,9 @@ class HTTPSServer(HTTPServer): self.socket = ssl.wrap_socket( self.socket, self.key, self.certificate, server_side=True, + cert_reqs=ssl.CERT_REQUIRED if self.certificate_authority else + ssl.CERT_NONE, + ca_certs=self.certificate_authority or None, ssl_version=self.protocol, ciphers=self.ciphers) self.server_bind() @@ -187,6 +191,9 @@ class RequestHandler(wsgiref.simple_server.WSGIRequestHandler): def get_environ(self): env = super().get_environ() + if hasattr(self.connection, "getpeercert"): + # The certificate can be evaluated by the auth module + env["REMOTE_CERTIFICATE"] = self.connection.getpeercert() # Parent class only tries latin1 encoding env["PATH_INFO"] = unquote(self.path.split("?", 1)[0]) return env diff --git a/radicale/__main__.py b/radicale/__main__.py index cd3cf6c..70e1945 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -169,11 +169,15 @@ def serve(configuration, logger): server_class = ThreadedHTTPSServer server_class.certificate = configuration.get("server", "certificate") server_class.key = configuration.get("server", "key") + server_class.certificate_authority = configuration.get( + "server", "certificate_authority") server_class.ciphers = configuration.get("server", "ciphers") server_class.protocol = getattr( ssl, configuration.get("server", "protocol"), ssl.PROTOCOL_SSLv23) # Test if the SSL files can be read - for name in ("certificate", "key"): + for name in ["certificate", "key"] + ( + ["certificate_authority"] + if server_class.certificate_authority else []): filename = getattr(server_class, name) try: open(filename, "r").close() diff --git a/radicale/config.py b/radicale/config.py index 3db0e5b..4b7ea4d 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -74,6 +74,11 @@ INITIAL_CONFIG = OrderedDict([ "help": "set private key file", "aliases": ["-k", "--key"], "type": str}), + ("certificate_authority", { + "value": "", + "help": "set CA certificate for validating clients", + "aliases": ["--certificate-authority"], + "type": str}), ("protocol", { "value": "PROTOCOL_TLSv1_2", "help": "SSL protocol used",