From d5f5eeeddfffad2a7a759c58eae0a92ab896171a Mon Sep 17 00:00:00 2001 From: Unrud Date: Wed, 22 Apr 2020 19:20:24 +0200 Subject: [PATCH] from_file rights: Replace config parser interpolation --- DOCUMENTATION.md | 20 +++++++++++--------- radicale/rights/from_file.py | 23 ++++++++++++----------- radicale/tests/test_rights.py | 2 +- rights | 4 ++-- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 958e3d2..8245e82 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -932,14 +932,14 @@ permissions: R # Allow reading and writing principal collection (same as user name) [principal] user: .+ -collection: %(login)s +collection: {user} permissions: RW # Allow reading and writing calendars and address books that are direct # children of the principal collection [calendars] user: .+ -collection: %(login)s/[^/]+ +collection: {user}/[^/]+ permissions: rw ``` @@ -955,16 +955,18 @@ users). The path of the collection is separated by `/` and has no leading or trailing `/`. Therefore, the path of the root collection is empty. -`%(login)s` gets replaced by the user name and `%(path)s` by the path of -the collection. You can also use groups from the `user` regex in the -`collection` regex with `{1}`, `{2}`, etc. +In the `collection` regex you can use `{user}` and get groups from the `user` +regex with `{0}`, `{1}`, etc. + +In consequence of the parameter subsitution you have to write `{{` and `}}` +if you want to use regular curly braces in the `user` and `collection` regexes. The following `permissions` are recognized: - * **R**: read a collection (excluding address book or calendar collections) - * **r**: read an address book or calendar collection - * **W**: write a collection (excluding address book or calendar collections) - * **w**: write an address book or calendar collection + * **R:** read a collection (excluding address book or calendar collections) + * **r:** read an address book or calendar collection + * **W:** write a collection (excluding address book or calendar collections) + * **w:** write an address book or calendar collection ## Storage diff --git a/radicale/rights/from_file.py b/radicale/rights/from_file.py index 82aaeb4..d6626fb 100644 --- a/radicale/rights/from_file.py +++ b/radicale/rights/from_file.py @@ -17,12 +17,13 @@ """ Rights backend based on a regex-based file whose name is specified in the -config (section "right", key "file"). +config (section "rights", key "file"). -Authentication login is matched against the "user" key, and collection's path -is matched against the "collection" key. You can use Python's ConfigParser -interpolation values %(login)s and %(path)s. You can also get groups from the -user regex in the collection with {0}, {1}, etc. +The login is matched against the "user" key, and the collection path +is matched against the "collection" key. In the "collection" regex you can use +`{user}` and get groups from the "user" regex with `{0}`, `{1}`, etc. +In consequence of the parameter subsitution you have to write `{{` and `}}` +if you want to use regular curly braces in the "user" and "collection" regexes. For example, for the "user" key, ".+" means "authenticated user" and ".*" means "anybody" (including anonymous users). @@ -49,10 +50,8 @@ class Rights(rights.BaseRights): user = user or "" sane_path = pathutils.strip_path(path) # Prevent "regex injection" - user_escaped = re.escape(user) - sane_path_escaped = re.escape(sane_path) - rights_config = configparser.ConfigParser( - {"login": user_escaped, "path": sane_path_escaped}) + escaped_user = re.escape(user) + rights_config = configparser.ConfigParser() try: if not rights_config.read(self._filename): raise RuntimeError("No such file: %r" % @@ -64,10 +63,12 @@ class Rights(rights.BaseRights): try: user_pattern = rights_config.get(section, "user") collection_pattern = rights_config.get(section, "collection") - user_match = re.fullmatch(user_pattern, user) + # Use empty format() for harmonized handling of curly braces + user_match = re.fullmatch(user_pattern.format(), user) collection_match = user_match and re.fullmatch( collection_pattern.format( - *map(re.escape, user_match.groups())), sane_path) + *map(re.escape, user_match.groups()), + user=escaped_user), sane_path) except Exception as e: raise RuntimeError("Error in section %r of rights file %r: " "%s" % (section, self._filename, e)) from e diff --git a/radicale/tests/test_rights.py b/radicale/tests/test_rights.py index ebe821a..28d959d 100644 --- a/radicale/tests/test_rights.py +++ b/radicale/tests/test_rights.py @@ -125,7 +125,7 @@ class TestBaseRightsRequests(BaseTest): f.write("""\ [owner] user: .+ -collection: %(login)s(/.*)? +collection: {user}(/.*)? permissions: RrWw [custom] user: .* diff --git a/rights b/rights index 9037993..7670be1 100644 --- a/rights +++ b/rights @@ -21,14 +21,14 @@ # Allow reading and writing principal collection (same as user name) #[principal] #user: .+ -#collection: %(login)s +#collection: {user} #permissions: RW # Allow reading and writing calendars and address books that are direct # children of the principal collection #[calendars] #user: .+ -#collection: %(login)s/[^/]+ +#collection: {user}/[^/]+ #permissions: rw