From 2a9f37defb145383f0c572cbe45ea3b2201a343f Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 2 Sep 2016 14:41:31 +0200 Subject: [PATCH 1/8] Repair authentication --- radicale/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/__init__.py b/radicale/__init__.py index 234e0ef..06354d9 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -388,7 +388,7 @@ class Application: self.logger.info("%s refused" % (user or "Anonymous user")) status = client.UNAUTHORIZED realm = self.configuration.get("server", "realm") - headers = headers.copy() + headers = dict(headers) headers.update ({ "WWW-Authenticate": "Basic realm=\"%s\"" % realm}) From 11df2f11842cc4bf2fc198d6e6eb394abd33422a Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 2 Sep 2016 14:42:22 +0200 Subject: [PATCH 2/8] Test authentication Test for 2a9f37defb145383f0c572cbe45ea3b2201a343f --- radicale/tests/test_base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index f7d2e81..ee47169 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -766,6 +766,14 @@ class BaseRequestsMixIn: assert status == 207 assert "href>/user/<" in answer + def test_authentication(self): + """Test if server sends authentication request.""" + self.configuration.set("rights", "type", "owner_only") + self.application = Application(self.configuration, self.logger) + status, headers, answer = self.request("MKCOL", "/user/") + assert status in (401, 403) + assert headers.get("WWW-Authenticate") + def test_principal_collection_creation(self): """Verify existence of the principal collection.""" status, headers, answer = self.request( From b25a601e28768a88ef55cd2d37fa100ba5474e28 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 2 Sep 2016 14:52:45 +0200 Subject: [PATCH 3/8] Test custom header --- radicale/tests/test_base.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index f7d2e81..d08b588 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -836,6 +836,17 @@ class BaseRequestsMixIn: except Exception: pass + def test_custom_headers(self): + if not self.configuration.has_section("headers"): + self.configuration.add_section("headers") + self.configuration.set("headers", "test", "123") + # Test if header is set on success + status, headers, answer = self.request("GET", "/") + assert headers.get("test") == "123" + # Test if header is set on failure + status, headers, answer = self.request("GET", "/.well-known/does not exist") + assert headers.get("test") == "123" + class BaseFileSystemTest(BaseTest): """Base class for filesystem backend tests.""" From 9e27d4e2a8719033d6e1bde865ad0bc99c92d8b0 Mon Sep 17 00:00:00 2001 From: Unrud Date: Fri, 2 Sep 2016 15:06:32 +0200 Subject: [PATCH 4/8] Emulate fullmatch with match re.fullmatch was introduced in Python 3.4 --- radicale/rights.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/radicale/rights.py b/radicale/rights.py index bad50a9..0092843 100644 --- a/radicale/rights.py +++ b/radicale/rights.py @@ -134,10 +134,12 @@ class Rights(BaseRights): self.logger.debug( "Test if '%s:%s' matches against '%s:%s' from section '%s'", user, sane_path, re_user, re_collection, section) - user_match = re.fullmatch(re_user, user) + # Emulate fullmatch + user_match = re.match(r"(?:%s)\Z" % re_user, user) if user_match: re_collection = re_collection.format(*user_match.groups()) - if re.fullmatch(re_collection, sane_path): + # Emulate fullmatch + if re.match(r"(?:%s)\Z" % re_collection, sane_path): self.logger.debug("Section '%s' matches", section) return permission in regex.get(section, "permission") else: From fe5daf801a890fff8b9530ddf9e6297f8b26799a Mon Sep 17 00:00:00 2001 From: Unrud Date: Sat, 3 Sep 2016 10:01:52 +0200 Subject: [PATCH 5/8] Set password to empty string instead of None Prevent exception in auth module. --- radicale/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/__init__.py b/radicale/__init__.py index 06354d9..c5266e8 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -338,7 +338,7 @@ class Application: user = self.Auth.map_login_to_user(login) else: user = self.Auth.map_login_to_user(environ.get("REMOTE_USER", "")) - password = None + password = "" # If "/.well-known" is not available, clients query "/" if path == "/.well-known" or path.startswith("/.well-known/"): From 26e58cee56639d56aa1e90ca4623e60350eae009 Mon Sep 17 00:00:00 2001 From: Unrud Date: Sat, 3 Sep 2016 10:18:07 +0200 Subject: [PATCH 6/8] Use hexadecimal for thread Old: ... - 139891659843328 - INFO: Starting Radicale New: ... - [7f3b10b12700] INFO: Starting Radicale --- logging | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging b/logging index 5943118..a3b99f1 100644 --- a/logging +++ b/logging @@ -57,4 +57,4 @@ format = %(message)s [formatter_full] # Full output format -format = %(asctime)s - %(thread)d - %(levelname)s: %(message)s +format = %(asctime)s - [%(thread)x] %(levelname)s: %(message)s From d371179487c37017de3c79c155a7f235fb3f964b Mon Sep 17 00:00:00 2001 From: Unrud Date: Sat, 3 Sep 2016 10:19:29 +0200 Subject: [PATCH 7/8] thread and level in simple log formatter The log messages are a mess without any allocation to threads. --- logging | 2 +- radicale/log.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/logging b/logging index a3b99f1..250359c 100644 --- a/logging +++ b/logging @@ -53,7 +53,7 @@ formatter = full [formatter_simple] # Simple output format -format = %(message)s +format = [%(thread)x] %(levelname)s: %(message)s [formatter_full] # Full output format diff --git a/radicale/log.py b/radicale/log.py index 34d4e4c..f550b48 100644 --- a/radicale/log.py +++ b/radicale/log.py @@ -56,7 +56,8 @@ def start(name="radicale", filename=None, debug=False): "Logging configuration file '%s' not found, using stderr." % filename) handler = logging.StreamHandler(sys.stderr) - handler.setFormatter(logging.Formatter("%(message)s")) + handler.setFormatter( + logging.Formatter("[%(thread)x] %(levelname)s: %(message)s")) logger.addHandler(handler) if debug: logger.setLevel(logging.DEBUG) From def34b14543af00e256074017bf96bda3b59f6b4 Mon Sep 17 00:00:00 2001 From: Unrud Date: Thu, 15 Sep 2016 11:18:55 +0200 Subject: [PATCH 8/8] Fix BaseCollection.move The update method doesn't exist. --- radicale/storage.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/radicale/storage.py b/radicale/storage.py index d102e6e..4aae415 100644 --- a/radicale/storage.py +++ b/radicale/storage.py @@ -254,10 +254,7 @@ class BaseCollection: """ if item.collection.path == to_collection.path and item.href == to_href: return - if to_collection.has(to_href): - to_collection.update(to_href, item.item) - else: - to_collection.upload(to_href, item.item) + to_collection.upload(to_href, item.item) item.collection.delete(item.href) @property