summaryrefslogtreecommitdiff
path: root/common/src/leap
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2013-08-31 15:47:40 -0300
committerdrebs <drebs@leap.se>2013-09-18 11:24:55 -0300
commitc51e243917c9cfd5859de9f42fcb9943a94ab096 (patch)
treefd2113fbcc70b27db2f4558d2cafa2cdd6dd51fe /common/src/leap
parent710130799a2a843309be0306862780f0f108b5dd (diff)
Add couch permission check.
Diffstat (limited to 'common/src/leap')
-rw-r--r--common/src/leap/soledad/common/couch.py93
-rw-r--r--common/src/leap/soledad/common/tests/test_server.py3
2 files changed, 93 insertions, 3 deletions
diff --git a/common/src/leap/soledad/common/couch.py b/common/src/leap/soledad/common/couch.py
index 9642e8f3..973f8b49 100644
--- a/common/src/leap/soledad/common/couch.py
+++ b/common/src/leap/soledad/common/couch.py
@@ -21,6 +21,8 @@
import uuid
import re
import simplejson as json
+import socket
+import logging
from base64 import b64encode, b64decode
@@ -30,7 +32,7 @@ from u1db.backends.inmemory import InMemoryIndex
from u1db.remote.server_state import ServerState
from u1db.errors import DatabaseDoesNotExist
from couchdb.client import Server, Document as CouchDocument
-from couchdb.http import ResourceNotFound
+from couchdb.http import ResourceNotFound, Unauthorized
from leap.soledad.common.objectstore import (
@@ -39,6 +41,9 @@ from leap.soledad.common.objectstore import (
)
+logger = logging.getLogger(__name__)
+
+
class InvalidURLError(Exception):
"""
Exception raised when Soledad encounters a malformed URL.
@@ -410,6 +415,15 @@ class CouchSyncTarget(ObjectStoreSyncTarget):
"""
Functionality for using a CouchDatabase as a synchronization target.
"""
+ pass
+
+
+class NotEnoughCouchPermissions(Exception):
+ """
+ Raised when failing to assert for enough permissions on underlying Couch
+ Database.
+ """
+ pass
class CouchServerState(ServerState):
@@ -417,8 +431,83 @@ class CouchServerState(ServerState):
Inteface of the WSGI server with the CouchDB backend.
"""
- def __init__(self, couch_url):
+ def __init__(self, couch_url, shared_db_name, tokens_db_name,
+ user_db_prefix):
+ """
+ Initialize the couch server state.
+
+ @param couch_url: The URL for the couch database.
+ @type couch_url: str
+ @param shared_db_name: The name of the shared database.
+ @type shared_db_name: str
+ @param tokens_db_name: The name of the tokens database.
+ @type tokens_db_name: str
+ @param user_db_prefix: The prefix for user database names.
+ @type user_db_prefix: str
+ """
self._couch_url = couch_url
+ self._shared_db_name = shared_db_name
+ self._tokens_db_name = tokens_db_name
+ self._user_db_prefix = user_db_prefix
+ try:
+ self._check_couch_permissions()
+ except NotEnoughCouchPermissions:
+ logger.error("Not enough permissions on underlying couch "
+ "database (%s)." % self._couch_url)
+ except (socket.error, socket.gaierror, socket.herror,
+ socket.timeout), e:
+ logger.error("Socket problem while trying to reach underlying "
+ "couch database: (%s, %s)." %
+ (self._couch_url, e))
+
+ def _check_couch_permissions(self):
+ """
+ Assert that Soledad Server has enough permissions on the underlying couch
+ database.
+
+ Soledad Server has to be able to do the following in the couch server:
+
+ * Create, read and write from/to 'shared' db.
+ * Create, read and write from/to 'user-<anything>' dbs.
+ * Read from 'tokens' db.
+
+ This function tries to perform the actions above using the "low level"
+ couch library to ensure that Soledad Server can do everything it needs on
+ the underlying couch database.
+
+ @param couch_url: The URL of the couch database.
+ @type couch_url: str
+
+ @raise NotEnoughCouchPermissions: Raised in case there are not enough
+ permissions to read/write/create the needed couch databases.
+ @rtype: bool
+ """
+
+ def _open_couch_db(dbname):
+ server = Server(url=self._couch_url)
+ try:
+ server[dbname]
+ except ResourceNotFound:
+ server.create(dbname)
+ return server[dbname]
+
+ def _create_delete_test_doc(db):
+ doc_id, _ = db.save({'test': 'document'})
+ doc = db[doc_id]
+ db.delete(doc)
+
+ try:
+ # test read/write auth for shared db
+ _create_delete_test_doc(
+ _open_couch_db(self._shared_db_name))
+ # test read/write auth for user-<something> db
+ _create_delete_test_doc(
+ _open_couch_db('%stest-db' % self._user_db_prefix))
+ # test read auth for tokens db
+ tokensdb = _open_couch_db(self._tokens_db_name)
+ tokensdb.info()
+ except Unauthorized:
+ raise NotEnoughCouchPermissions(self._couch_url)
def open_database(self, dbname):
"""
diff --git a/common/src/leap/soledad/common/tests/test_server.py b/common/src/leap/soledad/common/tests/test_server.py
index beb7e04d..1ea4d615 100644
--- a/common/src/leap/soledad/common/tests/test_server.py
+++ b/common/src/leap/soledad/common/tests/test_server.py
@@ -310,7 +310,8 @@ class EncryptedSyncTestCase(
secret_id=secret_id)
def make_app(self):
- self.request_state = CouchServerState(self._couch_url)
+ self.request_state = CouchServerState(
+ self._couch_url, 'shared', 'tokens', 'user-')
return self.make_app_with_state(self.request_state)
def setUp(self):