diff --git a/authserv/server.py b/authserv/server.py index c5be265fbecf86695c4357921dfb14b54fa3068d..6a4bfe5d98b1aac852fe77514bab77af4df2e7fa 100644 --- a/authserv/server.py +++ b/authserv/server.py @@ -1,7 +1,12 @@ +import logging +import optparse +import os +import signal from authserv import app from authserv import auth from authserv import protocol from authserv.ratelimit import * +from authserv import ssl from flask import Flask, request, abort, make_response @@ -65,3 +70,59 @@ def create_app(userdb=None, mc=None): app.memcache = mc return app + + +def main(): + parser = optparse.OptionParser() + parser.add_option('--config', + help='Configuration file') + parser.add_option('--port', type='int', default=1616, + help='TCP port to listen on (default: %default)') + parser.add_option('--ca', dest='ssl_ca', + default='/etc/ai/internal_ca.pem', + help='SSL CA certificate file (default: %default)') + parser.add_option('--ssl-cert', dest='ssl_cert', + default='/etc/ai/localhost_internal.pem', + help='SSL client certificate file (default: %default)') + parser.add_option('--ssl-key', dest='ssl_key', + default='/etc/ai/localhost_internal.key', + help='SSL client key file (default: %default)') + parser.add_option('--dhparams', dest='dh_params', + default='/etc/ai/dhparams', + help='Diffie-Helmann parameters file') + parser.add_option('--debug', action='store_true') + + opts, args = parser.parse_args() + if len(args) != 0: + parser.error('Too many arguments') + + if opts.debug: + logging.basicConfig(level=logging.DEBUG) + else: + handler = logging.handlers.SysLogHandler( + address='/dev/log', + facility=logging.handlers.SysLogHandler.LOG_DAEMON) + handler.setLevel(logging.INFO) + logging.getLogger().addHandler(handler) + + if opts.config: + os.setenv('APP_CONFIG', opts.config) + app.config.update({'DEBUG': opts.debug}) + + def _stopall(signo, frame): + logging.info('terminating with signal %d', signo) + os._exit(0) + signal.signal(signal.SIGINT, _stopall) + signal.signal(signal.SIGTERM, _stopall) + + ssl_ctx = None + if opts.ssl_ca and os.path.exists(opts.ssl_ca): + ssl_ctx = ssl.create_server_context(opts.ssl_cert, opts.ssl_key, + opts.ssl_ca, opts.dh_params) + + app.run(host='0.0.0.0', port=opts.port, use_reloader=False, + ssl_context=ssl_ctx) + + +if __name__ == '__main__': + main() diff --git a/authserv/ssl.py b/authserv/ssl.py new file mode 100644 index 0000000000000000000000000000000000000000..f03b3b2ea89da467a0d91cb6cc9602be4bb7794e --- /dev/null +++ b/authserv/ssl.py @@ -0,0 +1,29 @@ +from OpenSSL import crypto, SSL + + +def create_server_context(ssl_cert, ssl_key, ssl_ca, dhparams): + ctx = SSL.Context(SSL.TLSv1_METHOD) + ctx.use_privatekey_file(ssl_key) + ctx.use_certificate_file(ssl_cert) + if dhparams and os.path.exists(dhparams): + ctx.load_tmp_dh(dhparams) + #ctx.set_cipher_list('ECDHE-ECDSA-AES256-SHA384') + #ctx.set_cipher_list('DHE-RSA-AES256-SHA') + + with open(ssl_ca) as fd: + ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, fd.read()) + ctx.get_cert_store().add_cert(ca_cert) + + def verify_callback(connection, x509, errnum, errdepth, ok): + # Nothing else to do, valid CA signature has already been verified. + #print 'verify_callback(%s, %s, %s, %s, %s)' % ( + # connection, x509, errnum, errdepth, ok) + return ok + + ctx.set_verify(SSL.VERIFY_PEER + | SSL.VERIFY_FAIL_IF_NO_PEER_CERT + | SSL.VERIFY_CLIENT_ONCE, + verify_callback) + return ctx + + diff --git a/setup.py b/setup.py index fb541eefe6e983f7b65824705b12a8524c49475a..3f6807f545f3d10d7a6dd1f7ab59a2869a53506f 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( author="Autistici/Inventati", author_email="info@autistici.org", url="https://git.autistici.org/ai/authserv", - install_requires=["python-ldap", "Flask", "python-memcached", "nose"], + install_requires=["python-ldap", "PyOpenSSL", "Flask", "python-memcached", "nose"], setup_requires=[], zip_safe=False, packages=find_packages(),