From d022428a695ba5c499fcd0c8a9681962c006b8e8 Mon Sep 17 00:00:00 2001 From: drebs Date: Fri, 24 May 2013 12:59:21 -0300 Subject: Add action validation in server. * Use routes for validating user actions when interacting with server. * Also add tests for action validation. * Add changes file. * Closes #2356. --- src/leap/soledad/tests/test_leap_backend.py | 8 +- src/leap/soledad/tests/test_server.py | 242 ++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 src/leap/soledad/tests/test_server.py (limited to 'src/leap/soledad/tests') diff --git a/src/leap/soledad/tests/test_leap_backend.py b/src/leap/soledad/tests/test_leap_backend.py index 2e4b3b01..458fc5d5 100644 --- a/src/leap/soledad/tests/test_leap_backend.py +++ b/src/leap/soledad/tests/test_leap_backend.py @@ -35,12 +35,13 @@ from u1db.remote import ( http_database, http_target, ) +from routes.mapper import Mapper from leap import soledad from leap.soledad.backends import leap_backend from leap.soledad.server import ( SoledadApp, - SoledadAuthMiddleware + SoledadAuthMiddleware, ) from leap.soledad import auth @@ -78,8 +79,13 @@ def make_token_soledad_app(state): return True return False + # we test for action authorization in leap.soledad.tests.test_server + def verify_action(environ, uuid): + return True + application = SoledadAuthMiddleware(app) application.verify_token = verify_token + application.verify_action = verify_action return application diff --git a/src/leap/soledad/tests/test_server.py b/src/leap/soledad/tests/test_server.py new file mode 100644 index 00000000..d574b50e --- /dev/null +++ b/src/leap/soledad/tests/test_server.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +# test_server.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +""" +Tests for server-related functionality. +""" + +import os +import shutil +import tempfile +try: + import simplejson as json +except ImportError: + import json # noqa +import hashlib + + +from leap.soledad.server import URLToAuth +from leap.common.testing.basetest import BaseLeapTest + + +class SoledadServerTestCase(BaseLeapTest): + """ + Tests that guarantee that data will always be encrypted when syncing. + """ + + def setUp(self): + pass + + def tearDown(self): + pass + + def _make_environ(self, path_info, request_method): + return { + 'PATH_INFO': path_info, + 'REQUEST_METHOD': request_method, + } + + def test_verify_action_with_correct_dbnames(self): + """ + Test encrypting and decrypting documents. + + The following table lists the authorized actions among all possible + u1db remote actions: + + URL path | Authorized actions + -------------------------------------------------- + / | GET + /shared-db | GET + /shared-db/docs | - + /shared-db/doc/{id} | GET, PUT, DELETE + /shared-db/sync-from/{source} | - + /user-db | GET, PUT, DELETE + /user-db/docs | - + /user-db/doc/{id} | - + /user-db/sync-from/{source} | GET, PUT, POST + """ + uuid = 'myuuid' + authmap = URLToAuth(uuid) + dbname = authmap._uuid_dbname(uuid) + # test global auth + self.assertTrue( + authmap.is_authorized(self._make_environ('/', 'GET'))) + # test shared-db database resource auth + self.assertTrue( + authmap.is_authorized( + self._make_environ('/shared', 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared', 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared', 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared', 'POST'))) + # test shared-db docs resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/docs', 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/docs', 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/docs', 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/docs', 'POST'))) + # test shared-db doc resource auth + self.assertTrue( + authmap.is_authorized( + self._make_environ('/shared/doc/x', 'GET'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/shared/doc/x', 'PUT'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/shared/doc/x', 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/doc/x', 'POST'))) + # test shared-db sync resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/sync-from/x', 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/sync-from/x', 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/sync-from/x', 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/shared/sync-from/x', 'POST'))) + # test user-db database resource auth + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'GET'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'PUT'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'POST'))) + # test user-db docs resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'POST'))) + # test user-db doc resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'POST'))) + # test user-db sync resource auth + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'GET'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'DELETE'))) + self.assertTrue( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'POST'))) + + def test_verify_action_with_wrong_dbnames(self): + """ + Test if authorization fails for a wrong dbname. + """ + uuid = 'myuuid' + authmap = URLToAuth(uuid) + dbname = 'somedb' + # test wrong-db database resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s' % dbname, 'POST'))) + # test wrong-db docs resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/docs' % dbname, 'POST'))) + # test wrong-db doc resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/doc/x' % dbname, 'POST'))) + # test wrong-db sync resource auth + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'GET'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'PUT'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'DELETE'))) + self.assertFalse( + authmap.is_authorized( + self._make_environ('/%s/sync-from/x' % dbname, 'POST'))) -- cgit v1.2.3 From fdb52571378d1e6d522a74ad29833114a7eccd2e Mon Sep 17 00:00:00 2001 From: drebs Date: Sat, 25 May 2013 10:34:14 -0300 Subject: Remove unneeded exceptions. --- src/leap/soledad/tests/test_crypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/soledad/tests') diff --git a/src/leap/soledad/tests/test_crypto.py b/src/leap/soledad/tests/test_crypto.py index d35fc1c1..72eac6eb 100644 --- a/src/leap/soledad/tests/test_crypto.py +++ b/src/leap/soledad/tests/test_crypto.py @@ -44,7 +44,7 @@ from leap.soledad.backends.leap_backend import ( WrongMac, ) from leap.soledad.backends.couch import CouchDatabase -from leap.soledad import KeyAlreadyExists, Soledad +from leap.soledad import Soledad from leap.soledad.crypto import SoledadCrypto from leap.soledad.tests import BaseSoledadTest from leap.soledad.tests.test_couch import CouchDBTestCase -- cgit v1.2.3 From 6be80318adc9f1323b0b83651107810ac481511e Mon Sep 17 00:00:00 2001 From: drebs Date: Sat, 25 May 2013 10:39:32 -0300 Subject: Enforce dependency on simplejson. --- src/leap/soledad/tests/test_couch.py | 5 +---- src/leap/soledad/tests/test_crypto.py | 5 +---- src/leap/soledad/tests/test_leap_backend.py | 6 ++---- src/leap/soledad/tests/test_server.py | 5 +---- src/leap/soledad/tests/test_soledad.py | 5 +---- src/leap/soledad/tests/test_sqlcipher.py | 7 +++---- 6 files changed, 9 insertions(+), 24 deletions(-) (limited to 'src/leap/soledad/tests') diff --git a/src/leap/soledad/tests/test_couch.py b/src/leap/soledad/tests/test_couch.py index d6b9ad83..b3cbc1bc 100644 --- a/src/leap/soledad/tests/test_couch.py +++ b/src/leap/soledad/tests/test_couch.py @@ -31,10 +31,7 @@ from leap.soledad.backends import couch from leap.soledad.tests import u1db_tests as tests from leap.soledad.tests.u1db_tests import test_backends from leap.soledad.tests.u1db_tests import test_sync -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json from leap.soledad.backends.leap_backend import ( LeapDocument, ) diff --git a/src/leap/soledad/tests/test_crypto.py b/src/leap/soledad/tests/test_crypto.py index 72eac6eb..5432856e 100644 --- a/src/leap/soledad/tests/test_crypto.py +++ b/src/leap/soledad/tests/test_crypto.py @@ -23,10 +23,7 @@ Tests for cryptographic related stuff. import os import shutil import tempfile -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json import hashlib diff --git a/src/leap/soledad/tests/test_leap_backend.py b/src/leap/soledad/tests/test_leap_backend.py index 458fc5d5..d04ee412 100644 --- a/src/leap/soledad/tests/test_leap_backend.py +++ b/src/leap/soledad/tests/test_leap_backend.py @@ -23,12 +23,10 @@ Test Leap backend bits. import u1db import os import ssl -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json import cStringIO + from u1db.sync import Synchronizer from u1db.remote import ( http_client, diff --git a/src/leap/soledad/tests/test_server.py b/src/leap/soledad/tests/test_server.py index d574b50e..ec3f636b 100644 --- a/src/leap/soledad/tests/test_server.py +++ b/src/leap/soledad/tests/test_server.py @@ -23,10 +23,7 @@ Tests for server-related functionality. import os import shutil import tempfile -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json import hashlib diff --git a/src/leap/soledad/tests/test_soledad.py b/src/leap/soledad/tests/test_soledad.py index 5eef039f..1c0e6d4a 100644 --- a/src/leap/soledad/tests/test_soledad.py +++ b/src/leap/soledad/tests/test_soledad.py @@ -24,10 +24,7 @@ Tests for general Soledad functionality. import os import re import tempfile -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json from leap.common.testing.basetest import BaseLeapTest diff --git a/src/leap/soledad/tests/test_sqlcipher.py b/src/leap/soledad/tests/test_sqlcipher.py index 5bfb8de6..b0ec97a0 100644 --- a/src/leap/soledad/tests/test_sqlcipher.py +++ b/src/leap/soledad/tests/test_sqlcipher.py @@ -24,11 +24,10 @@ Test sqlcipher backend internals. import os import time import unittest -try: - import simplejson as json -except ImportError: - import json # noqa +import simplejson as json import threading + + from pysqlcipher import dbapi2 from StringIO import StringIO -- cgit v1.2.3 From 6238f80b9d9c8ea7091e196ccb69371050fd45db Mon Sep 17 00:00:00 2001 From: drebs Date: Sat, 25 May 2013 11:08:44 -0300 Subject: Add token credentials to SQLCipher tests. --- src/leap/soledad/tests/test_sqlcipher.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/leap/soledad/tests') diff --git a/src/leap/soledad/tests/test_sqlcipher.py b/src/leap/soledad/tests/test_sqlcipher.py index b0ec97a0..dfc5577b 100644 --- a/src/leap/soledad/tests/test_sqlcipher.py +++ b/src/leap/soledad/tests/test_sqlcipher.py @@ -439,6 +439,7 @@ def sync_via_synchronizer_and_leap(test, db_source, db_target, test.skipTest("full trace hook unsupported over http") path = test._http_at[db_target] target = LeapSyncTarget.connect(test.getURL(path), test._soledad._crypto) + target.set_token_credentials('user-uuid', 'auth-token') if trace_hook_shallow: target._set_trace_hook_shallow(trace_hook_shallow) return sync.Synchronizer(db_source, target).sync() @@ -662,6 +663,7 @@ def _make_local_db_and_leap_target(test, path='test'): test.startServer() db = test.request_state._create_database(os.path.basename(path)) st = LeapSyncTarget.connect(test.getURL(path), test._soledad._crypto) + st.set_token_credentials('user-uuid', 'auth-token') return db, st -- cgit v1.2.3