diff options
| author | drebs <drebs@leap.se> | 2013-02-26 19:16:09 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2013-02-26 19:16:09 -0300 | 
| commit | f5616981e8ba043da71a21371c2cbfc5fcb5da56 (patch) | |
| tree | e472ebf66847205c2fb9fe570e3d59e2d181852d /server.py | |
| parent | fa4c1786f1dde0235ba27f2804ae6e3e1fcc8389 (diff) | |
Add auth middleware structure for soledad.
Diffstat (limited to 'server.py')
| -rw-r--r-- | server.py | 89 | 
1 files changed, 86 insertions, 3 deletions
| @@ -6,16 +6,91 @@ This should be run with:  """  import configparser +from wsgiref.util import shift_path_info +  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") +        token = environ.get('HTTP_AUTHORIZATION') +        if not token: +            if need_auth(environ): +                return self._error(start_response, 401, "unauthorized", +                                   "Missing Authentication Token.") +        else: +            try: +                self.verify_token(environ, token) +            except Unauthorized: +                return self._error( +                    start_response, 401, "unauthorized", +                    "Incorrect password or login.") +            del environ['HTTP_AUTHORIZATION'] +        shift_path_info(environ) +        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_user) + +    def need_auth(self, environ): +        """ +        Check if action can be performed on database without authentication. +        """ +        # TODO: implement unauth verification. +        raise NotImplementedError(self.allow_unauth) + + +#----------------------------------------------------------------------------- +# 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) @@ -23,14 +98,22 @@ def load_configuration(file_path):          for key in conf:              if key in config['soledad-server']:                  conf[key] = config['soledad-server'][key] +    # TODO: implement basic parsing of options comming from config file.      return conf -conf = load_configuration('/etc/leap/soledad-server.ini') +#----------------------------------------------------------------------------- +# Run as Twisted WSGI Resource +#----------------------------------------------------------------------------- +conf = load_configuration('/etc/leap/soledad-server.ini')  state = CouchServerState(conf['couch_url']) -# TODO: change working dir to something meaningful +# TODO: change working dir to something meaningful (maybe eliminate it)  state.set_workingdir(conf['working_dir']) -application = http_app.HTTPApp(state) + +application = SoledadAuthMiddleware( +    http_app.HTTPApp(state), +    conf['prefix'], +    conf['public_dbs'].split(','))  resource = WSGIResource(reactor, reactor.getThreadPool(), application) | 
