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
from configparser import ConfigParser
from importlib import import_module
from io import StringIO
from . import storage
def load(configuration, logger):
"""Load the rights manager chosen in configuration."""
auth_type = configuration.get("auth", "type")
rights_type = configuration.get("rights", "type")
if auth_type == "None" or rights_type == "None":
return lambda user, collection, permission: True
elif rights_type in DEFINED_RIGHTS or rights_type == "from_file":
return Rights(configuration, logger).authorized
if configuration.get("auth", "type") == "None":
rights_type = "None"
logger.info("Rights type is %r", rights_type)
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:
module = import_module(rights_type)
return module.Rights(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
"""}
rights_class = import_module(rights_type).Rights
return rights_class(configuration, logger).authorized
class BaseRights:
@ -102,31 +80,47 @@ class BaseRights:
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):
def __init__(self, configuration, logger):
super().__init__(configuration, logger)
self.filename = os.path.expanduser(configuration.get("rights", "file"))
self.rights_type = configuration.get("rights", "type").lower()
def authorized(self, user, path, permission):
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("/")
# Prevent "regex injection"
user_escaped = re.escape(user)
sane_path_escaped = re.escape(sane_path)
regex = ConfigParser(
{"login": user_escaped, "path": sane_path_escaped})
if self.rights_type in DEFINED_RIGHTS:
self.logger.debug("Rights type '%s'", self.rights_type)
regex.readfp(StringIO(DEFINED_RIGHTS[self.rights_type]))
else:
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)
raise RuntimeError("Failed to read rights from file %r",
self.filename)
return False
for section in regex.sections():