Jelajahi Sumber

Merge pull request #1646 from TownCube/fix-issue-1611

Fix 'Replacement index 0 out of range for positional args tuple'
Peter Bieringer 1 tahun lalu
induk
melakukan
eef33f76d1

+ 1 - 1
DOCUMENTATION.md

@@ -888,7 +888,7 @@ Default: `(cn={0})`
 Load the ldap groups of the authenticated user. These groups can be used later on to define rights. This also gives you access to the group calendars, if they exist.
 Load the ldap groups of the authenticated user. These groups can be used later on to define rights. This also gives you access to the group calendars, if they exist.
 * The group calendar will be placed under collection_root_folder/GROUPS
 * The group calendar will be placed under collection_root_folder/GROUPS
 * The name of the calendar directory is the base64 encoded group name.
 * The name of the calendar directory is the base64 encoded group name.
-* The group calneder folders will not be created automaticaly. This must be created manualy. [Here](https://github.com/Kozea/Radicale/wiki/LDAP-authentication) you can find a script to create group calneder folders https://github.com/Kozea/Radicale/wiki/LDAP-authentication
+* The group calendar folders will not be created automaticaly. This must be created manually. [Here](https://github.com/Kozea/Radicale/wiki/LDAP-authentication) you can find a script to create group calendar folders https://github.com/Kozea/Radicale/wiki/LDAP-authentication
 
 
 Default: False
 Default: False
 
 

+ 2 - 1
radicale/rights/from_file.py

@@ -84,7 +84,8 @@ class Rights(rights.BaseRights):
                     collection_pattern.format(
                     collection_pattern.format(
                         *(re.escape(s) for s in user_match.groups()),
                         *(re.escape(s) for s in user_match.groups()),
                         user=escaped_user), sane_path)
                         user=escaped_user), sane_path)
-                group_collection_match = re.fullmatch(collection_pattern.format(user=escaped_user), sane_path)
+                group_collection_match = group_match and re.fullmatch(
+                    collection_pattern.format(user=escaped_user), sane_path)
             except Exception as e:
             except Exception as e:
                 raise RuntimeError("Error in section %r of rights file %r: "
                 raise RuntimeError("Error in section %r of rights file %r: "
                                    "%s" % (section, self._filename, e)) from e
                                    "%s" % (section, self._filename, e)) from e

+ 2 - 1
radicale/tests/__init__.py

@@ -29,6 +29,7 @@ import wsgiref.util
 import xml.etree.ElementTree as ET
 import xml.etree.ElementTree as ET
 from io import BytesIO
 from io import BytesIO
 from typing import Any, Dict, List, Optional, Tuple, Union
 from typing import Any, Dict, List, Optional, Tuple, Union
+from urllib.parse import quote
 
 
 import defusedxml.ElementTree as DefusedET
 import defusedxml.ElementTree as DefusedET
 import vobject
 import vobject
@@ -167,7 +168,7 @@ class BaseTest:
         assert answer is not None
         assert answer is not None
         responses = self.parse_responses(answer)
         responses = self.parse_responses(answer)
         if kwargs.get("HTTP_DEPTH", "0") == "0":
         if kwargs.get("HTTP_DEPTH", "0") == "0":
-            assert len(responses) == 1 and path in responses
+            assert len(responses) == 1 and quote(path) in responses
         return status, responses
         return status, responses
 
 
     def proppatch(self, path: str, data: Optional[str] = None,
     def proppatch(self, path: str, data: Optional[str] = None,

+ 14 - 4
radicale/tests/test_rights.py

@@ -30,10 +30,10 @@ class TestBaseRightsRequests(BaseTest):
     def _test_rights(self, rights_type: str, user: str, path: str, mode: str,
     def _test_rights(self, rights_type: str, user: str, path: str, mode: str,
                      expected_status: int, with_auth: bool = True) -> None:
                      expected_status: int, with_auth: bool = True) -> None:
         assert mode in ("r", "w")
         assert mode in ("r", "w")
-        assert user in ("", "tmp")
+        assert user in ("", "tmp", "user@domain.test")
         htpasswd_file_path = os.path.join(self.colpath, ".htpasswd")
         htpasswd_file_path = os.path.join(self.colpath, ".htpasswd")
         with open(htpasswd_file_path, "w") as f:
         with open(htpasswd_file_path, "w") as f:
-            f.write("tmp:bepo\nother:bepo")
+            f.write("tmp:bepo\nother:bepo\nuser@domain.test:bepo")
         self.configure({
         self.configure({
             "rights": {"type": rights_type},
             "rights": {"type": rights_type},
             "auth": {"type": "htpasswd" if with_auth else "none",
             "auth": {"type": "htpasswd" if with_auth else "none",
@@ -42,8 +42,9 @@ class TestBaseRightsRequests(BaseTest):
         for u in ("tmp", "other"):
         for u in ("tmp", "other"):
             # Indirect creation of principal collection
             # Indirect creation of principal collection
             self.propfind("/%s/" % u, login="%s:bepo" % u)
             self.propfind("/%s/" % u, login="%s:bepo" % u)
+        os.makedirs(os.path.join(self.colpath, "collection-root", "domain.test"), exist_ok=True)
         (self.propfind if mode == "r" else self.proppatch)(
         (self.propfind if mode == "r" else self.proppatch)(
-            path, check=expected_status, login="tmp:bepo" if user else None)
+            path, check=expected_status, login="%s:bepo" % user if user else None)
 
 
     def test_owner_only(self) -> None:
     def test_owner_only(self) -> None:
         self._test_rights("owner_only", "", "/", "r", 401)
         self._test_rights("owner_only", "", "/", "r", 401)
@@ -110,14 +111,23 @@ permissions: RrWw
 [custom]
 [custom]
 user: .*
 user: .*
 collection: custom(/.*)?
 collection: custom(/.*)?
-permissions: Rr""")
+permissions: Rr
+[read-domain-principal]
+user: .+@([^@]+)
+collection: {0}
+permissions: R""")
         self.configure({"rights": {"file": rights_file_path}})
         self.configure({"rights": {"file": rights_file_path}})
         self._test_rights("from_file", "", "/other/", "r", 401)
         self._test_rights("from_file", "", "/other/", "r", 401)
+        self._test_rights("from_file", "tmp", "/tmp/", "r", 207)
         self._test_rights("from_file", "tmp", "/other/", "r", 403)
         self._test_rights("from_file", "tmp", "/other/", "r", 403)
         self._test_rights("from_file", "", "/custom/sub", "r", 404)
         self._test_rights("from_file", "", "/custom/sub", "r", 404)
         self._test_rights("from_file", "tmp", "/custom/sub", "r", 404)
         self._test_rights("from_file", "tmp", "/custom/sub", "r", 404)
         self._test_rights("from_file", "", "/custom/sub", "w", 401)
         self._test_rights("from_file", "", "/custom/sub", "w", 401)
         self._test_rights("from_file", "tmp", "/custom/sub", "w", 403)
         self._test_rights("from_file", "tmp", "/custom/sub", "w", 403)
+        self._test_rights("from_file", "tmp", "/custom/sub", "w", 403)
+        self._test_rights("from_file", "user@domain.test", "/domain.test/", "r", 207)
+        self._test_rights("from_file", "user@domain.test", "/tmp/", "r", 403)
+        self._test_rights("from_file", "user@domain.test", "/other/", "r", 403)
 
 
     def test_from_file_limited_get(self):
     def test_from_file_limited_get(self):
         rights_file_path = os.path.join(self.colpath, "rights")
         rights_file_path = os.path.join(self.colpath, "rights")