From cc9537b9c73c6f502dc4576df0aee4409e887d47 Mon Sep 17 00:00:00 2001 From: drebs Date: Thu, 25 Apr 2013 23:15:06 -0300 Subject: Add token auth infrastructure. --- src/leap/soledad/__init__.py | 4 +-- src/leap/soledad/backends/leap_backend.py | 12 ++++++++ src/leap/soledad/server.py | 46 ++++++++++++++++--------------- 3 files changed, 38 insertions(+), 24 deletions(-) (limited to 'src/leap/soledad') diff --git a/src/leap/soledad/__init__.py b/src/leap/soledad/__init__.py index a736d32b..06f7c755 100644 --- a/src/leap/soledad/__init__.py +++ b/src/leap/soledad/__init__.py @@ -667,7 +667,7 @@ class Soledad(object): """ return self._db.resolve_doc(doc, conflicted_doc_revs) - def sync(self, url): + def sync(self, url, creds=None): """ Synchronize the local encrypted replica with a remote replica. @@ -679,7 +679,7 @@ class Soledad(object): @rtype: str """ # TODO: create authentication scheme for sync with server. - local_gen = self._db.sync(url, creds=None, autocreate=True) + local_gen = self._db.sync(url, creds=creds, autocreate=True) events.signal(events.events_pb2.SOLEDAD_DONE_DATA_SYNC, self._address) return local_gen diff --git a/src/leap/soledad/backends/leap_backend.py b/src/leap/soledad/backends/leap_backend.py index 05c27bc1..51c471eb 100644 --- a/src/leap/soledad/backends/leap_backend.py +++ b/src/leap/soledad/backends/leap_backend.py @@ -394,3 +394,15 @@ class LeapSyncTarget(HTTPSyncTarget): res = self._parse_sync_stream(data, return_doc_cb, ensure_callback) data = None return res['new_generation'], res['new_transaction_id'] + + def set_token_credentials(self, address, token): + self._creds = {'token': (address, token)} + + def _sign_request(self, method, url_query, params): + if 'token' in self._creds: + address, token = self._creds['token'] + auth = '%s:%s' % (address, token) + return [('Authorization', 'Token %s' % auth.encode('base64'))] + else: + return HTTPSyncTarget._sign_request( + self, method, url_query, params) diff --git a/src/leap/soledad/server.py b/src/leap/soledad/server.py index fdb98916..3d3c6f69 100644 --- a/src/leap/soledad/server.py +++ b/src/leap/soledad/server.py @@ -116,36 +116,34 @@ class SoledadAuthMiddleware(object): """ if self.prefix and not environ['PATH_INFO'].startswith(self.prefix): return self._error(start_response, 400, "bad request") + auth = environ.get('HTTP_AUTHORIZATION') + if not auth: + return self._error(start_response, 401, "unauthorized", + "Missing Token Authentication.") + scheme, encoded = auth.split(None, 1) + if scheme.lower() != 'token': + return self._error( + start_response, 401, "unauthorized", + "Missing Token Authentication") + address, token = encoded.decode('base64').split(':', 1) + try: + self.verify_token(environ, address, token) + except Unauthorized: + return self._error( + start_response, 401, "unauthorized", + "Incorrect address or token.") + del environ['HTTP_AUTHORIZATION'] 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): + def verify_token(self, environ, address, token): """ Verify if token is valid for authenticating this request. @param environ: Dictionary containing CGI variables. @type environ: dict + @param token: The user address. + @type token: str @param token: The authentication token. @type token: str @@ -195,6 +193,10 @@ class SoledadApp(http_app.HTTPApp): @return: HTTP application results. @rtype: list """ + # TODO: this is a hack for tests to pass, we should remove it asap. + #if environ['CONTENT_LENGTH'] == '': + # environ['CONTENT_LENGTH'] = 1 + #import ipdb; ipdb.set_trace() return http_app.HTTPApp.__call__(self, environ, start_response) -- cgit v1.2.3