diff options
| author | drebs <drebs@joselito.semvergonha.org> | 2013-03-07 16:34:22 -0300 | 
|---|---|---|
| committer | drebs <drebs@joselito.semvergonha.org> | 2013-03-07 16:34:22 -0300 | 
| commit | 1b1def113e6ed9b8af6897e16f0d9b4c96bbfa6b (patch) | |
| tree | c34b751dde12bc92628165e8af902da54e39e898 /server.py | |
| parent | 4672ec4f25daa6466b2850bea416eaf77fa90d9d (diff) | |
Move source files to subfolder.
Diffstat (limited to 'server.py')
| -rw-r--r-- | server.py | 151 | 
1 files changed, 0 insertions, 151 deletions
| diff --git a/server.py b/server.py deleted file mode 100644 index eaa5e964..00000000 --- a/server.py +++ /dev/null @@ -1,151 +0,0 @@ -# -*- coding: utf-8 -*- -""" -A U1DB server that stores data using couchdb. - -This should be run with: -    twistd -n web --wsgi=leap.soledad.server.application -""" - -import configparser -from wsgiref.util import shift_path_info -import httplib -try: -    import simplejson as json -except ImportError: -    import json  # noqa -from urlparse import parse_qs - -from twisted.web.wsgi import WSGIResource -from twisted.internet import reactor - -from u1db.remote import http_app - -from leap.soledad.backends.couch import CouchServerState - - -#----------------------------------------------------------------------------- -# Authentication -#----------------------------------------------------------------------------- - -class Unauthorized(Exception): -    """ -    User authentication failed. -    """ - - -class SoledadAuthMiddleware(object): -    """ -    Soledad Authentication WSGI middleware. - -    In general, databases are accessed using a token provided by the LEAP API. -    Some special databases can be read without authentication. -    """ - -    def __init__(self, app, prefix, public_dbs=None): -        self.app = app -        self.prefix = prefix -        self.public_dbs = public_dbs - -    def _error(self, start_response, status, description, message=None): -        start_response("%d %s" % (status, httplib.responses[status]), -                       [('content-type', 'application/json')]) -        err = {"error": description} -        if message: -            err['message'] = message -        return [json.dumps(err)] - -    def __call__(self, environ, start_response): -        if self.prefix and not environ['PATH_INFO'].startswith(self.prefix): -            return self._error(start_response, 400, "bad request") -        shift_path_info(environ) -        qs = parse_qs(environ.get('QUERY_STRING'), strict_parsing=True) -        if 'auth_token' not in qs: -            if self.need_auth(environ): -                return self._error(start_response, 401, "unauthorized", -                                   "Missing Authentication Token.") -        else: -            token = qs['auth_token'][0] -            try: -                self.verify_token(environ, token) -            except Unauthorized: -                return self._error( -                    start_response, 401, "unauthorized", -                    "Incorrect password or login.") -            # remove auth token from query string. -            del qs['auth_token'] -            qs_str = '' -            if qs: -                qs_str = reduce(lambda x, y: '&'.join([x, y]), -                                map(lambda (x, y): '='.join([x, str(y)]), -                                    qs.iteritems())) -            environ['QUERY_STRING'] = qs_str -        return self.app(environ, start_response) - -    def verify_token(self, environ, token): -        """ -        Verify if token is valid for authenticating this action. -        """ -        # TODO: implement token verification -        raise NotImplementedError(self.verify_token) - -    def need_auth(self, environ): -        """ -        Check if action can be performed on database without authentication. - -        For now, just allow access to /shared/*. -        """ -        # TODO: design unauth verification. -        return not environ.get('PATH_INFO').startswith('/shared/') - - -#----------------------------------------------------------------------------- -# Soledad WSGI application -#----------------------------------------------------------------------------- - -class SoledadApp(http_app.HTTPApp): -    """ -    Soledad WSGI application -    """ - -    def __call__(self, environ, start_response): -        return super(SoledadApp, self).__call__(environ, start_response) - - -#----------------------------------------------------------------------------- -# Auxiliary functions -#----------------------------------------------------------------------------- - -def load_configuration(file_path): -    conf = { -        'couch_url': 'http://localhost:5984', -        'working_dir': '/tmp', -        'public_dbs': 'keys', -        'prefix': '/soledad/', -    } -    config = configparser.ConfigParser() -    config.read(file_path) -    if 'soledad-server' in config: -        for key in conf: -            if key in config['soledad-server']: -                conf[key] = config['soledad-server'][key] -    # TODO: implement basic parsing/sanitization of options comming from -    # config file. -    return conf - - -#----------------------------------------------------------------------------- -# Run as Twisted WSGI Resource -#----------------------------------------------------------------------------- - -# TODO: create command-line option for choosing config file. -conf = load_configuration('/etc/leap/soledad-server.ini') -state = CouchServerState(conf['couch_url']) -# TODO: change working dir to something meaningful (maybe eliminate it) -state.set_workingdir(conf['working_dir']) - -application = SoledadAuthMiddleware( -    SoledadApp(state), -    conf['prefix'], -    conf['public_dbs'].split(',')) - -resource = WSGIResource(reactor, reactor.getThreadPool(), application) | 
