diff --git a/README.rst b/README.rst index a10f428..3597ed4 100644 --- a/README.rst +++ b/README.rst @@ -18,18 +18,18 @@ version 3 for distribution. Features -------- -TODO: improve this part - - * Filters: You can filter the request or the response with one or many filters. - You can serve static response in a filter. - There 3 types of filters: - * on_request - * on_response - * reponse - * Dispatcher: This will call the right filters - * Authentification management - * Sql and ldap authentification - * Authentification through Authentic2 idp (SAML2 and CAS) + * Mapping / dispatching:: + With Mandaye you can define your own mapping files. This allows you to call your own filters + on the right HTTP requests. See the config part for more details. + * Filters:: + You can define your own filters with Mandaye. This filter have access to the WSGI environment and + could modify the HTTP requests and / or responses. + * Local authentification:: + Mandaye provide a sql local authentification but you can also implement your own + local authentification. + * Distant authentification:: + At the moment Mandaye only support form replay for a distant authentification but we will provide + SAML 2.0, OpenID and CAS support. Installation @@ -40,52 +40,72 @@ Dependencies You must install the following packages to use Mandaye - * Gevent 0.13:: - - From sources: http://pypi.python.org/pypi/gevent - Debian based distribution: apt-get install python-gevent - - * Poster 0.8:: - - From sources: http://pypi.python.org/pypi/poster/ - Debian based distribution: apt-get install python-poster - - * SQLAlchemy 0.7.2:: - - From sources: http://pypi.python.org/pypi/SQLAlchemy - - * Beaker 1.5.4:: - - From sources: http://pypi.python.org/pypi/Beaker - - * Mako 0.4.2:: - - From sources: http://pypi.python.org/pypi/Mako - - * lxml 2.3.1:: - - From sources: http://pypi.python.org/pypi/lxml + * Python >= 2.5:: http://python.org/ + * Setuptools >= 0.6:: http://pypi.python.org/pypi/setuptools + * Gunicorn >= 0.13:: http://pypi.python.org/pypi/gunicorn + * Poster >= 0.8:: http://pypi.python.org/pypi/poster/ + * SQLAlchemy >= 0.7:: http://pypi.python.org/pypi/SQLAlchemy + * Beaker >= 1.6:: http://pypi.python.org/pypi/Beaker + * Mako >= 0.4:: http://pypi.python.org/pypi/Mako + * lxml >= 2.3:: http://pypi.python.org/pypi/lxml You can install all those dependencies quickly using pip:: - pip install gevent poster SQLAlchemy Beaker Mako lxml + pip install gevent poster SQLAlchemy Beaker Mako lxml gunicorn or easy_install:: - easy_install gevent poster SQLAlchemy Beaker Mako lxml + easy_install gevent poster SQLAlchemy Beaker Mako lxml gunicorn + +or apt-get (Debian based distributions):: + + apt-get install gunicorn python-poster python-sqlalchemy python-beaker python-mako python-lxml python-setuptools + +It's recommanded to install the following modules + + * PyCrypto >= 2.3:: http://pypi.python.org/pypi/pycrypto + * Static >= 0.4:: http://pypi.python.org/pypi/static + + You can install this Python modules with pip:: + + pip install pycrypto static + +Quick installation +------------------ + +Install at least Python >=2.5 and setuptools or distribute and enter this command in a shell:: + + $ python setup.py install + +If you want to develop use this command line:: + + $ python setup.py develop + Quick Start ----------- -Configure mandaye/config.py +Configure MANDAYE_PATH/mandaye/config.py with your own preferences. +You must configure the database uri and the log file. -Then launch the following commands:: +First create your database:: - ./mandayectl --createdb - ./mandayectl --start + $ mandaye_admin.py --createdb -You should see the following output:: +Launch mandaye server::: - Database created - Starting Mandaye x.x.x.x:xx ... + $ mandaye_server.py +mandaye_server.py use gunicorn and gunicorn options (please read http://gunicorn.org/configure.html) + +You could alse use gunicorn.conf.py-sample (in the mandaye files):: + + $ mandaye_server.py -c PATH_TO_THE_FILE/gunicorn.conf.py + +or:: + + $ mandaye_server.py -c PATH_TO_THE_FILE/gunicorn.conf.py -b 0.0.0.0:4242 + +Configuration +============= +TODO diff --git a/crypt_pwd.py b/crypt_pwd.py deleted file mode 100755 index 69a787b..0000000 --- a/crypt_pwd.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" Script to crypt mandaye passwords -""" - -import base64 -import logging - -from Crypto.Cipher import AES -from mandaye import config -from mandaye.models import ExtUser -from mandaye.db import sql_session - -def encrypt_pwd(pwd): - logging.debug("Encrypt password") - enc_pwd = pwd - if config.encrypt_secret: - try: - cipher = AES.new(config.encrypt_secret, AES.MODE_CFB) - enc_pwd = cipher.encrypt(pwd) - enc_pwd = base64.b64encode(enc_pwd) - except Exception, e: - if config.debug: - traceback.print_exc() - logging.warning('Password encrypting failed %s' % e) - else: - logging.warning("You must set a secret to use pwd encryption") - return enc_pwd - -for user in sql_session().query(ExtUser).all(): - user.password = encrypt_pwd(user.password) - -sql_session().commit() - diff --git a/gunicorn.conf.py-sample b/gunicorn.conf.py-sample new file mode 100644 index 0000000..43634e1 --- /dev/null +++ b/gunicorn.conf.py-sample @@ -0,0 +1,23 @@ + +PID_DIR = '/var/run/' + +# Gunicorn configuration (http://gunicorn.org/configure.html) +#bind = '127.0.0.1:8000' # Default bind +#bind = 'unix:%s/mandaye.sock' % PID_DIR # Unix socket + +#pidfile = '%s/mandaye.pid' % PID_DIR +timeout = 60 +worker = 4 +worker_class = 'sync' +#worker_connections = 1000 # The maximum number of simultaneous clients +#max_requests = 0 # The maximum number of requests a worker will process before restarting + +# User / Group +#user = 'www-data' +#group = 'www-data' + +# Log +loglevel = "info" +accesslog = '/var/log/mandaye/mandaye-access.log' +errorlog = "/var/log/mandaye/mandaye-gunicorn.log" + diff --git a/mandaye/__init__.py b/mandaye/__init__.py index 8152610..d17ccaa 100644 --- a/mandaye/__init__.py +++ b/mandaye/__init__.py @@ -1,4 +1,4 @@ -VERSION=0.1 +VERSION=0.2 import logging from logging import FileHandler diff --git a/mandaye/config.py b/mandaye/config.py index 28672a9..5ea38f0 100644 --- a/mandaye/config.py +++ b/mandaye/config.py @@ -1,10 +1,6 @@ -from logging import DEBUG +import logging from mandaye.exceptions import ImproperlyConfigured -# Mandaye configuration -host = '127.0.0.1' -port = 8088 - # Needed if ssl is activated ssl = False keyfile = '' @@ -13,8 +9,8 @@ certfile = '' # Log configuration debug = False syslog = False -log_level = DEBUG -log_file = '/tmp/mandaye.log' +log_file = '/var/log/mandaye/mandaye.log' +log_level = logging.INFO # Template directory template_directory = 'mandaye/templates' diff --git a/mandaye/server.py b/mandaye/server.py index 549f70e..27c9bb7 100644 --- a/mandaye/server.py +++ b/mandaye/server.py @@ -1,8 +1,4 @@ -# gevent patching -#from gevent import monkey -#monkey.patch_all() - import Cookie import config import logging @@ -16,7 +12,6 @@ import time from beaker.middleware import SessionMiddleware from cgi import escape -from gevent.pywsgi import WSGIServer, WSGIHandler from static import Cling from mandaye.config import debug @@ -172,23 +167,3 @@ class MandayeApp(object): response.headers.items()) return [response.msg] -class ServerHandler(WSGIHandler): - - def log_request(self): - logging.info(self.format_request()) - -def serve(): - """Convenience function to immediately start a server instance.""" - wsgi_app = SessionMiddleware(MandayeApp(), config.session_opts) - if config.ssl: - s = WSGIServer((config.host, config.port), wsgi_app, - keyfile=config.keyfile, certfile=config.certfile, - handler_class=ServerHandler) - else: - s = WSGIServer((config.host, config.port), wsgi_app, - handler_class=ServerHandler) - try: - s.serve_forever() - except KeyboardInterrupt: - s.stop() - diff --git a/mandaye_admin.py b/mandaye_admin.py new file mode 100755 index 0000000..d5fa1e7 --- /dev/null +++ b/mandaye_admin.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" Script to administrate mandaye server +""" + +import base64 +import logging + +from optparse import OptionParser + +from Crypto.Cipher import AES +from mandaye import config +from mandaye.models import ExtUser +from mandaye.db import sql_session + + +def get_cmd_options(): + usage = "usage: %prog --createdb|--cryptpwd" + parser = OptionParser(usage=usage) + parser.add_option("--createdb", + dest="createdb", + default=False, + action="store_true", + help="Create the Mandaye database" + ) + parser.add_option("--cryptpwd", + dest="cryptpwd", + default=False, + action="store_true", + help="Crypt external password in Mandaye's database" + ) + (options, args) = parser.parse_args() + if not options.createdb: + parser.error("You must use option --createdb") + return options + +def encrypt_pwd(pwd): + logging.debug("Encrypt password") + enc_pwd = pwd + if config.encrypt_secret: + try: + cipher = AES.new(config.encrypt_secret, AES.MODE_CFB) + enc_pwd = cipher.encrypt(pwd) + enc_pwd = base64.b64encode(enc_pwd) + except Exception, e: + if config.debug: + traceback.print_exc() + logging.warning('Password encrypting failed %s' % e) + else: + logging.warning("You must set a secret to use pwd encryption") + return enc_pwd + +def main(): + options = get_cmd_options() + if options.createdb: + logging.info("Creating database...") + if config.db_url: + from mandaye.models import Base + from sqlalchemy import create_engine + engine = create_engine(config.db_url) + Base.metadata.create_all(engine) + logging.info("Database created") + if options.cryptpwd: + for user in sql_session().query(ExtUser).all(): + user.password = encrypt_pwd(user.password) + sql_session().commit() + +if __name__ == "__main__": + main() diff --git a/mandaye_server.py b/mandaye_server.py new file mode 100755 index 0000000..a9e6e73 --- /dev/null +++ b/mandaye_server.py @@ -0,0 +1,29 @@ +#!/home/jschneider/temp/test/bin/python +# -*- coding: utf-8 -*- + +""" Script to launch mandaye with gunicorn server +""" + +import logging +import sys +import os + +from gunicorn.app.wsgiapp import WSGIApplication + +class WSGIApplication(WSGIApplication): + + def init(self, parser, opts, args): + self.cfg.set("default_proc_name", "mandaye.wsgi:application") + self.app_uri = "mandaye.wsgi:application" + + sys.path.insert(0, os.getcwd()) + +def main(): + """ The ``gunicorn`` command line runner for launcing Gunicorn with + generic WSGI applications. + """ + logging.info('Launching Mandaye ...') + WSGIApplication("%prog [OPTIONS]").run() + +if __name__ == "__main__": + main() diff --git a/mandayectl b/mandayectl deleted file mode 100755 index 9272863..0000000 --- a/mandayectl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" Script to start and stop mandaye server -""" - -import logging - -from optparse import OptionParser - -from mandaye import config -from mandaye import server - -def get_cmd_options(): - usage = "usage: %prog --start|--createdb" - parser = OptionParser(usage=usage) - parser.add_option("--start", - dest="start", - default=False, - action="store_true", - help="Start Mandaye server" - ) - parser.add_option("--createdb", - dest="createdb", - default=False, - action="store_true", - help="Create the Mandaye database" - ) - (options, args) = parser.parse_args() - if not options.start and not options.createdb: - parser.error("You must use option --start | --createdb") - return options - -def main(): - options = get_cmd_options() - if options.createdb: - logging.info("Creating database...") - if config.db_url: - from mandaye.models import Base - from sqlalchemy import create_engine - engine = create_engine(config.db_url) - Base.metadata.create_all(engine) - print "Database created" - - if options.start: - print "Starting Mandaye %s:%d .." % (config.host, config.port) - server.serve() - -if __name__ == "__main__": - main() diff --git a/setup.py b/setup.py index dee6160..b1cb019 100644 --- a/setup.py +++ b/setup.py @@ -17,12 +17,12 @@ setup(name="mandaye", author_email="info@entrouvert.org", maintainer="Jerome Schneider", maintainer_email="jschneider@entrouvert.com", - scripts=['mandayectl'], + scripts=['mandaye_server.py', 'mandaye_admin.py'], packages=find_packages(), package_data={}, install_requires=[ 'beaker>=1.5', - 'gevent>=0.13', + 'gunicorn>=0.13', 'mako>=0.3', 'poster>=0.8', 'pycrypto>=2.0',