Implement rights types directly

This is faster and easier to understand.
This commit is contained in:
Unrud 2017-05-31 00:36:18 +02:00
parent 1bc53ec113
commit 5ce2c62402

View File

@ -41,51 +41,29 @@ import os.path
import re import re
from configparser import ConfigParser from configparser import ConfigParser
from importlib import import_module from importlib import import_module
from io import StringIO
from . import storage from . import storage
def load(configuration, logger): def load(configuration, logger):
"""Load the rights manager chosen in configuration.""" """Load the rights manager chosen in configuration."""
auth_type = configuration.get("auth", "type")
rights_type = configuration.get("rights", "type") rights_type = configuration.get("rights", "type")
if auth_type == "None" or rights_type == "None": if configuration.get("auth", "type") == "None":
return lambda user, collection, permission: True rights_type = "None"
elif rights_type in DEFINED_RIGHTS or rights_type == "from_file": logger.info("Rights type is %r", rights_type)
return Rights(configuration, logger).authorized if rights_type == "None":
rights_class = NoneRights
elif rights_type == "authenticated":
rights_class = AuthenticatedRights
elif rights_type == "owner_write":
rights_class = OwnerWriteRights
elif rights_type == "owner_only":
rights_class = OwnerOnlyRights
elif rights_type == "from_file":
rights_class = Rights
else: else:
module = import_module(rights_type) rights_class = import_module(rights_type).Rights
return module.Rights(configuration, logger).authorized return rights_class(configuration, logger).authorized
DEFINED_RIGHTS = {
"authenticated": """
[rw]
user:.+
collection:.*
permission:rw
""",
"owner_write": """
[w]
user:.+
collection:%(login)s(/.*)?
permission:rw
[r]
user:.+
collection:.*
permission:r
""",
"owner_only": """
[rw]
user:.+
collection:%(login)s(/.*)?
permission:rw
[r]
user:.+
collection:
permission:r
"""}
class BaseRights: class BaseRights:
@ -102,32 +80,48 @@ class BaseRights:
raise NotImplementedError raise NotImplementedError
class NoneRights(BaseRights):
def authorized(self, user, path, permission):
return True
class AuthenticatedRights(BaseRights):
def authorized(self, user, path, permission):
return bool(user)
class OwnerWriteRights(BaseRights):
def authorized(self, user, path, permission):
sane_path = storage.sanitize_path(path).strip("/")
return bool(user) and (permission == "r" or
user == sane_path.split("/", maxsplit=1)[0])
class OwnerOnlyRights(BaseRights):
def authorized(self, user, path, permission):
sane_path = storage.sanitize_path(path).strip("/")
return bool(user) and (
permission == "r" and not sane_path.strip("/") or
user == sane_path.split("/", maxsplit=1)[0])
class Rights(BaseRights): class Rights(BaseRights):
def __init__(self, configuration, logger): def __init__(self, configuration, logger):
super().__init__(configuration, logger) super().__init__(configuration, logger)
self.filename = os.path.expanduser(configuration.get("rights", "file")) self.filename = os.path.expanduser(configuration.get("rights", "file"))
self.rights_type = configuration.get("rights", "type").lower()
def authorized(self, user, path, permission): def authorized(self, user, path, permission):
user = user or "" user = user or ""
if user and not storage.is_safe_path_component(user):
# Prevent usernames like "user/calendar.ics"
raise ValueError("Refused unsafe username: %s", user)
sane_path = storage.sanitize_path(path).strip("/") sane_path = storage.sanitize_path(path).strip("/")
# Prevent "regex injection" # Prevent "regex injection"
user_escaped = re.escape(user) user_escaped = re.escape(user)
sane_path_escaped = re.escape(sane_path) sane_path_escaped = re.escape(sane_path)
regex = ConfigParser( regex = ConfigParser(
{"login": user_escaped, "path": sane_path_escaped}) {"login": user_escaped, "path": sane_path_escaped})
if self.rights_type in DEFINED_RIGHTS: if not regex.read(self.filename):
self.logger.debug("Rights type '%s'", self.rights_type) raise RuntimeError("Failed to read rights from file %r",
regex.readfp(StringIO(DEFINED_RIGHTS[self.rights_type])) self.filename)
else: return False
self.logger.debug("Reading rights from file '%s'", self.filename)
if not regex.read(self.filename):
self.logger.error(
"File '%s' not found for rights", self.filename)
return False
for section in regex.sections(): for section in regex.sections():
re_user = regex.get(section, "user") re_user = regex.get(section, "user")