diff --git a/config b/config index b1548cc..453a45e 100644 --- a/config +++ b/config @@ -96,10 +96,10 @@ http_password_parameter = [rights] # Rights management method -# Value: None | owner_only | owner_write | from_file | regex +# Value: None | owner_only | owner_write | from_file type = None -# File for rights management from_file or regex +# File for rights management from_file file = ~/.config/radicale/rights diff --git a/radicale/__init__.py b/radicale/__init__.py index 7bbe1dc..2dd6401 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -131,7 +131,6 @@ class Application(object): """Initialize application.""" super(Application, self).__init__() auth.load() - rights.load() storage.load() self.encoding = config.get("encoding", "request") if config.getboolean("logging", "full_environment"): @@ -190,7 +189,7 @@ class Application(object): for item in items: if isinstance(item, ical.Collection): - if rights.read_authorized(user, item): + if rights.authorized(user, item, "r"): log.LOGGER.debug( "%s has read access to collection %s" % (user or "Anonymous", item.url or "/")) @@ -202,7 +201,7 @@ class Application(object): (user or "Anonymous", item.url or "/")) read_last_collection_allowed = False - if rights.write_authorized(user, item): + if rights.authorized(user, item, "w"): log.LOGGER.debug( "%s has write access to collection %s" % (user or "Anonymous", item.url or "/")) diff --git a/radicale/config.py b/radicale/config.py index 45b758f..44d057e 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -74,7 +74,7 @@ INITIAL_CONFIG = { "http_password_parameter": ""}, "rights": { "type": "None", - "file": ""}, + "file": "~/.config/radicale/rights"}, "storage": { "type": "filesystem", "filesystem_folder": os.path.expanduser( diff --git a/radicale/rights/regex.py b/radicale/rights.py similarity index 51% rename from radicale/rights/regex.py rename to radicale/rights.py index 2b4f823..c41da5b 100644 --- a/radicale/rights/regex.py +++ b/radicale/rights.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- # # This file is part of Radicale Server - Calendar Server -# Copyright © 2013 Guillaume Ayoub +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter +# Copyright © 2008-2013 Guillaume Ayoub # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,60 +19,14 @@ # along with Radicale. If not, see . """ -Regex-based rights. - -Regexes are read from a file whose name is specified in the config (section -"right", 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. - -Section names are only used for naming the rule. - -Leading or ending slashes are trimmed from collection's path. - -Examples: - -# This means all users starting with "admin" may read any collection -[admin] -user: ^admin.*\|.+?$ -collection: .* -permission: r - -# This means all users may read and write any collection starting with public. -# We do so by just not testing against the user string. -[public] -user: .* -collection: ^public(/.+)?$ -permission: rw - -# A little more complex: give read access to users from a domain for all -# collections of all the users (ie. user@domain.tld can read domain/*). -[domain-wide-access] -user: ^.+@(.+)\..+$ -collection: ^{0}/.+$ -permission: r - -# Allow authenticated user to read all collections -[allow-everyone-read] -user: .* -collection: .* -permission: r - -# Give write access to owners -[owner-write] -user: .* -collection: ^%(login)s/.+$ -permission: w +Rights management. """ -import os.path import re +import os.path -from radicale import config, log +from . import config, log # Manage Python2/3 different modules # pylint: disable=F0401 @@ -84,16 +40,27 @@ except ImportError: FILENAME = ( os.path.expanduser(config.get("rights", "file")) or log.LOGGER.error("No file name configured for rights type 'regex'")) +DEFINED_RIGHTS = { + "none": "[rw]\nuser:.*\ncollection:.*\npermission:rw", + "owner_write": "[r]\nuser:.*\ncollection:.*\npermission:r\n" + "[w]\nuser:.*\ncollection:^%(login)s/.+$\npermission:w", + "owner_only": "[rw]\nuser:.\ncollection: ^%(login)s/.+$\npermission:rw"} def _read_from_sections(user, collection, permission): """Get regex sections.""" - log.LOGGER.debug("Reading regex from file %s" % FILENAME) regex = ConfigParser({"login": user, "path": collection}) - if not regex.read(FILENAME): - log.LOGGER.error( - "File '%s' not found for rights management type 'regex'" % - FILENAME) + rights_type = config.get("rights", "type").lower() + if rights_type in DEFINED_RIGHTS: + log.LOGGER.debug("Rights type '%s'" % rights_type) + regex.read_string(DEFINED_RIGHTS[rights_type]) + elif rights_type == "from_file": + log.LOGGER.debug("Reading rights from file %s" % FILENAME) + if not regex.read(FILENAME): + log.LOGGER.error("File '%s' not found for rights" % FILENAME) + return False + else: + log.LOGGER.error("Unknown rights type '%s'" % rights_type) return False for section in regex.sections(): @@ -110,17 +77,10 @@ def _read_from_sections(user, collection, permission): if permission in regex.get(section, "permission"): return True log.LOGGER.debug("Section '%s' does not match" % section) - return False -def read_authorized(user, collection): - """Check if the user is allowed to read the collection.""" +def authorized(user, collection, right): + """Check if the user is allowed to read or write the collection.""" return user and _read_from_sections( - user, collection.url.rstrip("/") or "/", "r") - - -def write_authorized(user, collection): - """Check if the user is allowed to write the collection.""" - return user and _read_from_sections( - user, collection.url.rstrip("/") or "/", "w") + user, collection.url.rstrip("/") or "/", right) diff --git a/radicale/rights/__init__.py b/radicale/rights/__init__.py deleted file mode 100644 index 78ee026..0000000 --- a/radicale/rights/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Radicale Server - Calendar Server -# Copyright © 2008 Nicolas Kandel -# Copyright © 2008 Pascal Halter -# Copyright © 2008-2013 Guillaume Ayoub -# -# This library is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Radicale. If not, see . - -""" -Rights management. - -""" - -import sys - -from .. import config, log - - -def load(): - """Load list of available ACL managers.""" - rights_type = config.get("rights", "type") - log.LOGGER.debug("Rights type is %s" % rights_type) - if rights_type == "None": - return None - else: - root_module = __import__( - "rights.%s" % rights_type, globals=globals(), level=2) - module = getattr(root_module, rights_type) - # Override rights.[read|write]_authorized - sys.modules[__name__].read_authorized = module.read_authorized - sys.modules[__name__].write_authorized = module.write_authorized - return module - - -def read_authorized(user, collection): - """Check if the user is allowed to read the collection. - - This method is overriden if an auth module is loaded. - - """ - return True - - -def write_authorized(user, collection): - """Check if the user is allowed to write the collection. - - This method is overriden if an auth module is loaded. - - """ - return True diff --git a/radicale/rights/from_file.py b/radicale/rights/from_file.py deleted file mode 100644 index e0eee24..0000000 --- a/radicale/rights/from_file.py +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Radicale Server - Calendar Server -# Copyright © 2012-2013 Guillaume Ayoub -# -# This library is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Radicale. If not, see . - -""" -File-based rights. - -The owners are implied to have all rights on their collections. - -Rights are read from a file whose name is specified in the config (section -"right", key "file"). - -Example: - -# This means user1 may read, user2 may write, user3 has full access. -[user0/calendar] -user1: r -user2: w -user3: rw - -# user0 can read user1/cal. -[user1/cal] -user0: r - -# If a collection a/b is shared and other users than the owner are supposed to -# find the collection in a propfind request, an additional line for a has to -# be in the defintions. -[user0] -user1: r - -""" - -import os.path - -from radicale import config, log -from radicale.rights import owner_only -# Manage Python2/3 different modules -# pylint: disable=F0401 -try: - from configparser import ( - RawConfigParser as ConfigParser, NoSectionError, NoOptionError) -except ImportError: - from ConfigParser import ( - RawConfigParser as ConfigParser, NoSectionError, NoOptionError) -# pylint: enable=F0401 - - -FILENAME = ( - os.path.expanduser(config.get("rights", "file")) or - log.LOGGER.error("No file name configured for rights type 'from_file'")) - - -def _read_rights(): - """Update the rights according to the configuration file.""" - log.LOGGER.debug("Reading rights from file %s" % FILENAME) - rights = ConfigParser() - if not rights.read(FILENAME): - log.LOGGER.error( - "File '%s' not found for rights management" % FILENAME) - return rights - - -def read_authorized(user, collection): - """Check if the user is allowed to read the collection.""" - if user is None: - return False - elif owner_only.read_authorized(user, collection): - return True - else: - try: - return "r" in _read_rights().get( - collection.url.rstrip("/") or "/", user) - except (NoSectionError, NoOptionError): - return False - - -def write_authorized(user, collection): - """Check if the user is allowed to write the collection.""" - if user is None: - return False - elif owner_only.write_authorized(user, collection): - return True - else: - try: - return "w" in _read_rights().get( - collection.url.rstrip("/") or "/", user) - except (NoSectionError, NoOptionError): - return False diff --git a/radicale/rights/owner_only.py b/radicale/rights/owner_only.py deleted file mode 100644 index ec4fb5a..0000000 --- a/radicale/rights/owner_only.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Radicale Server - Calendar Server -# Copyright © 2012-2013 Guillaume Ayoub -# -# This library is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Radicale. If not, see . - -""" -Owner-only based rights. - -Only owners have read and write access to their own collections. - -""" - - -def read_authorized(user, collection): - """Check if the user is allowed to read the collection.""" - return user == collection.owner - - -def write_authorized(user, collection): - """Check if the user is allowed to write the collection.""" - return user == collection.owner diff --git a/radicale/rights/owner_write.py b/radicale/rights/owner_write.py deleted file mode 100644 index 6031ad4..0000000 --- a/radicale/rights/owner_write.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Radicale Server - Calendar Server -# Copyright © 2012-2013 Guillaume Ayoub -# -# This library is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Radicale. If not, see . - -""" -Owner-only write based rights. - -Authenticated users have read access to all calendars, but only owners have -write access to their own collections. - -""" - - -def read_authorized(user, collection): - """Check if the user is allowed to read the collection.""" - return True - - -def write_authorized(user, collection): - """Check if the user is allowed to write the collection.""" - return user and user == collection.owner