diff --git a/authserv/ssl.py b/authserv/openssl.py similarity index 100% rename from authserv/ssl.py rename to authserv/openssl.py diff --git a/authserv/server.py b/authserv/server.py index 30efe4fde4000a7395c34f9761cb074120658386..6bf7f9f906a4fee6ad2f411bcd9249758ad3b2b7 100644 --- a/authserv/server.py +++ b/authserv/server.py @@ -6,7 +6,6 @@ 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 @@ -77,14 +76,64 @@ def create_app(userdb=None, mc=None): return app +def run_werkzeug(addr, port, ssl_ca, ssl_cert, ssl_key, dh_params): + ssl_ctx = None + if ssl_ca and os.path.exists(ssl_ca): + from authserv import openssl + ssl_ctx = openssl.create_server_context( + ssl_cert, ssl_key, ssl_ca, dhparams) + logging.info('starting werkzeug server on %s:%d', addr, port) + app.run(host=addr, port=port, use_reloader=False, ssl_context=ssl_ctx) + + +def run_gevent(addr, port, ssl_ca, ssl_cert, ssl_key, dh_params): + from gevent.monkey import patch_all + patch_all() + from gevent.pywsgi import WSGIServer + ssl_args = {} + if ssl_ca and os.path.exists(ssl_ca): + import ssl + ssl_args = { + 'server_side': True, + 'certfile': ssl_cert, + 'keyfile': ssl_key, + 'ca_certs': ssl_ca, + 'cert_reqs': ssl.CERT_REQUIRED, + 'ssl_version': ssl.PROTOCOL_TLSv1, + } + logging.info('starting gevent server on %s:%d', addr, port) + WSGIServer((addr, port), app.wsgi_app, **ssl_args).serve_forever() + + +def run(engines, addr, port, ssl_ca, ssl_cert, ssl_key, dh_params): + if engines: + engines = engines.split(',') + else: + engines = ['gevent', 'werkzeug'] + + for e in engines: + fn = globals().get('run_' + e, None) + if not fn: + logging.error('Unknown HTTP engine "%s"', e) + continue + try: + return fn(addr, port, ssl_ca, ssl_cert, ssl_key, dh_params) + except ImportError: + pass + + logging.fatal('No HTTP engine available to run the server') + + 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('--addr', dest='addr', default='0.0.0.0', help='Address to listen on (default: %default)') + parser.add_option('--port', type='int', default=1616, + help='TCP port to listen on (default: %default)') + parser.add_option('--engine', dest='engine', + help='HTTP engine to use (default: try gevent, then werkzeug)') parser.add_option('--ca', dest='ssl_ca', default='/etc/ai/internal_ca.pem', help='SSL CA certificate file (default: %default)') @@ -122,13 +171,8 @@ def main(): 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=opts.addr, port=opts.port, use_reloader=False, - ssl_context=ssl_ctx) + run(opts.engine, opts.addr, opts.port, opts.ssl_ca, + opts.ssl_cert, opts.ssl_key, opts.dh_params) if __name__ == '__main__': diff --git a/authserv/test/test_integration.py b/authserv/test/test_integration.py index f0660a53ae1bd807e200f032e092ac3cc9a2b532..80bb97ca9310cb26a45b641dcb712fb6f3e710fd 100644 --- a/authserv/test/test_integration.py +++ b/authserv/test/test_integration.py @@ -9,7 +9,6 @@ from authserv.test import * from authserv.ratelimit import * from authserv import protocol from authserv import server -from authserv import ssl URL = '/api/1/auth' @@ -70,10 +69,8 @@ class SSLServerTest(unittest.TestCase): pid = os.fork() if pid == 0: print >>sys.stderr, 'starting server on port %d' % self.port - ssl_ctx = ssl.create_server_context( - self.ssl_cert, self.ssl_key, self.ssl_ca, self.dhparams) - app.run(host='127.0.0.1', port=self.port, - use_reloader=False, ssl_context=ssl_ctx) + server.run(None, '127.0.0.1', self.port, self.ssl_ca, + self.ssl_cert, self.ssl_key, self.dhparams) else: self.pid = pid time.sleep(0.2)