summaryrefslogtreecommitdiff
path: root/server/src/leap
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2015-11-17 20:49:38 -0400
committerKali Kaneko <kali@leap.se>2015-11-17 20:49:38 -0400
commitaa6a34bc4ac5962dacaa5908778e444fe5aae3d7 (patch)
treed461ef588b88b1457dce537a0440660f467b6068 /server/src/leap
parent489d851e88151cd51df6725330515e6b8a2ea1b2 (diff)
parent46678a7aecb98dbdc20846477c7f5110f3c63861 (diff)
Merge branch 'develop' into debian/platform-0.8
Diffstat (limited to 'server/src/leap')
-rw-r--r--server/src/leap/soledad/server/__init__.py50
-rw-r--r--server/src/leap/soledad/server/auth.py55
-rw-r--r--server/src/leap/soledad/server/sync.py7
3 files changed, 34 insertions, 78 deletions
diff --git a/server/src/leap/soledad/server/__init__.py b/server/src/leap/soledad/server/__init__.py
index f64d07bf..00e1e9fb 100644
--- a/server/src/leap/soledad/server/__init__.py
+++ b/server/src/leap/soledad/server/__init__.py
@@ -94,12 +94,6 @@ from u1db.remote import http_app, utils
from ._version import get_versions
-# Keep OpenSSL's tsafe before importing Twisted submodules so we can put
-# it back if Twisted==12.0.0 messes with it.
-from OpenSSL import tsafe
-
-from twisted import version
-
from leap.soledad.server.auth import SoledadTokenAuthMiddleware
from leap.soledad.server.gzip_middleware import GzipMiddleware
from leap.soledad.server.lock_resource import LockResource
@@ -110,14 +104,7 @@ from leap.soledad.server.sync import (
)
from leap.soledad.common import SHARED_DB_NAME
-from leap.soledad.common.couch import CouchServerState
-
-old_tsafe = tsafe
-
-if version.base() == "12.0.0":
- # Put OpenSSL's tsafe back into place. This can probably be removed if we
- # come to use Twisted>=12.3.0.
- sys.modules['OpenSSL.tsafe'] = old_tsafe
+from leap.soledad.common.couch.state import CouchServerState
# ----------------------------------------------------------------------------
# Soledad WSGI application
@@ -272,6 +259,20 @@ http_app.HTTPInvocationByMethodWithBody = HTTPInvocationByMethodWithBody
# ----------------------------------------------------------------------------
# Auxiliary functions
# ----------------------------------------------------------------------------
+CONFIG_DEFAULTS = {
+ 'soledad-server': {
+ 'couch_url': 'http://localhost:5984',
+ 'create_cmd': None,
+ 'admin_netrc': '/etc/couchdb/couchdb-admin.netrc',
+ },
+ 'database-security': {
+ 'members': ['soledad'],
+ 'members_roles': [],
+ 'admins': [],
+ 'admins_roles': []
+ }
+}
+
def load_configuration(file_path):
"""
@@ -283,17 +284,19 @@ def load_configuration(file_path):
@return: A dictionary with the configuration.
@rtype: dict
"""
- defaults = {
- 'couch_url': 'http://localhost:5984',
- 'create_cmd': None,
- 'admin_netrc': '/etc/couchdb/couchdb-admin.netrc',
- }
+ defaults = dict(CONFIG_DEFAULTS)
config = configparser.ConfigParser()
config.read(file_path)
- if 'soledad-server' in config:
- for key in defaults:
- if key in config['soledad-server']:
- defaults[key] = config['soledad-server'][key]
+ for section in defaults.keys():
+ if section in config:
+ for key in defaults[section]:
+ if key in config[section]:
+ defaults[section][key] = config[section][key]
+ for key, value in defaults['database-security'].iteritems():
+ if type(value) is not unicode:
+ continue
+ defaults['database-security'][key] = \
+ [item.strip() for item in value.split(',')]
# TODO: implement basic parsing/sanitization of options comming from
# config file.
return defaults
@@ -305,6 +308,7 @@ def load_configuration(file_path):
def application(environ, start_response):
conf = load_configuration('/etc/soledad/soledad-server.conf')
+ conf = conf['soledad-server']
state = CouchServerState(conf['couch_url'], create_cmd=conf['create_cmd'])
# WSGI application that may be used by `twistd -web`
application = GzipMiddleware(
diff --git a/server/src/leap/soledad/server/auth.py b/server/src/leap/soledad/server/auth.py
index 02b54cca..ccbd6fbd 100644
--- a/server/src/leap/soledad/server/auth.py
+++ b/server/src/leap/soledad/server/auth.py
@@ -21,20 +21,16 @@ Authentication facilities for Soledad Server.
"""
-import time
import httplib
import json
from u1db import DBNAME_CONSTRAINTS, errors as u1db_errors
from abc import ABCMeta, abstractmethod
from routes.mapper import Mapper
-from couchdb.client import Server
from twisted.python import log
-from hashlib import sha512
from leap.soledad.common import SHARED_DB_NAME
from leap.soledad.common import USER_DB_PREFIX
-from leap.soledad.common.errors import InvalidAuthTokenError
class URLToAuthorization(object):
@@ -351,14 +347,12 @@ class SoledadTokenAuthMiddleware(SoledadAuthMiddleware):
Token based authentication.
"""
- TOKENS_DB_PREFIX = "tokens_"
- TOKENS_DB_EXPIRE = 30 * 24 * 3600 # 30 days in seconds
- TOKENS_TYPE_KEY = "type"
- TOKENS_TYPE_DEF = "Token"
- TOKENS_USER_ID_KEY = "user_id"
-
TOKEN_AUTH_ERROR_STRING = "Incorrect address or token."
+ def __init__(self, app):
+ self._state = app.state
+ super(SoledadTokenAuthMiddleware, self).__init__(app)
+
def _verify_authentication_scheme(self, scheme):
"""
Verify if authentication scheme is valid.
@@ -391,50 +385,11 @@ class SoledadTokenAuthMiddleware(SoledadAuthMiddleware):
"""
token = auth_data # we expect a cleartext token at this point
try:
- return self._verify_token_in_couch(uuid, token)
- except InvalidAuthTokenError:
- raise
+ return self._state.verify_token(uuid, token)
except Exception as e:
log.err(e)
return False
- def _verify_token_in_couch(self, uuid, token):
- """
- Query couchdb to decide if C{token} is valid for C{uuid}.
-
- @param uuid: The user uuid.
- @type uuid: str
- @param token: The token.
- @type token: str
-
- @raise InvalidAuthTokenError: Raised when token received from user is
- either missing in the tokens db or is
- invalid.
- """
- server = Server(url=self._app.state.couch_url)
- # the tokens db rotates every 30 days, and the current db name is
- # "tokens_NNN", where NNN is the number of seconds since epoch divided
- # by the rotate period in seconds. When rotating, old and new tokens
- # db coexist during a certain window of time and valid tokens are
- # replicated from the old db to the new one. See:
- # https://leap.se/code/issues/6785
- dbname = self.TOKENS_DB_PREFIX + \
- str(int(time.time() / self.TOKENS_DB_EXPIRE))
- db = server[dbname]
- # lookup key is a hash of the token to prevent timing attacks.
- token = db.get(sha512(token).hexdigest())
- if token is None:
- raise InvalidAuthTokenError()
- # we compare uuid hashes to avoid possible timing attacks that
- # might exploit python's builtin comparison operator behaviour,
- # which fails immediatelly when non-matching bytes are found.
- couch_uuid_hash = sha512(token[self.TOKENS_USER_ID_KEY]).digest()
- req_uuid_hash = sha512(uuid).digest()
- if token[self.TOKENS_TYPE_KEY] != self.TOKENS_TYPE_DEF \
- or couch_uuid_hash != req_uuid_hash:
- raise InvalidAuthTokenError()
- return True
-
def _get_auth_error_string(self):
"""
Get the error string for token auth.
diff --git a/server/src/leap/soledad/server/sync.py b/server/src/leap/soledad/server/sync.py
index 619be565..db25c406 100644
--- a/server/src/leap/soledad/server/sync.py
+++ b/server/src/leap/soledad/server/sync.py
@@ -32,7 +32,7 @@ class SyncExchange(sync.SyncExchange):
def __init__(self, db, source_replica_uid, last_known_generation, sync_id):
"""
:param db: The target syncing database.
- :type db: CouchDatabase
+ :type db: SoledadBackend
:param source_replica_uid: The uid of the source syncing replica.
:type source_replica_uid: str
:param last_known_generation: The last target replica generation the
@@ -185,15 +185,12 @@ class SyncResource(http_app.SyncResource):
:type ensure: bool
"""
# create or open the database
- cache = get_cache_for('db-' + sync_id + self.dbname)
+ cache = get_cache_for('db-' + sync_id + self.dbname, expire=120)
if ensure:
db, self.replica_uid = self.state.ensure_database(self.dbname)
- elif cache and 'instance' in cache:
- db = cache['instance']
else:
db = self.state.open_database(self.dbname)
db.init_caching(cache)
- cache['instance'] = db
# validate the information the client has about server replica
db.validate_gen_and_trans_id(
last_known_generation, last_known_trans_id)