| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- # -*- 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 <http://www.gnu.org/licenses/>.
- """
- Regex-based rights.
- You can define an secondary rights management method. If not, it will use
- "owner_only", which implies the owners have all rights on their collections.
- Secondary rights management method is specified in the config (section
- "right", key "regex_secondary").
- Regexes are read from a file whose name is specified in the config (section
- "right", key "regex_file").
- Test string for regex is "user|collection" per default, because "|" is
- not allowed in an URL. You may set this string per rule, using Python's
- ConfigParser interpolation: %(user)s and %(collection)s
- In fact you may also set user/collection to a fixed value per rule. But you
- should consider using a secondary rights management method (e.g. "from_file").
- Section names are only used for naming the rule.
- Leading or Ending "/"s are trimmed from collection names.
- Example:
- # This means all users starting with "admin" may read any collection
- [admin]
- regex: ^admin.*\|.+?$
- 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]
- glue: %(collection)s
- regex: ^public(/.+)?$
- permission: rw
- # A little more complex:
- # Give read access to users from a domain for all collections of all the users:
- [domain-wide-access]
- regex: ^.+@(.+)\|.+@\1(/.+)?$
- permission: r
- """
- import os.path
- import re
- from radicale import config, log, rights
- # Manage Python2/3 different modules
- # pylint: disable=F0401
- try:
- from configparser import (
- ConfigParser as ConfigParser, NoSectionError, NoOptionError)
- except ImportError:
- from ConfigParser import (
- ConfigParser as ConfigParser, NoSectionError, NoOptionError)
- # pylint: enable=F0401
- FILENAME = (
- os.path.expanduser(config.get("rights", "regex_file")) or
- log.LOGGER.error("No file name configured for rights type 'regex'"))
-
-
- def _read_regex(user, collection):
- """Load regex from file."""
- regex = ConfigParser({'user': user, 'collection': collection})
- if not regex.read(FILENAME):
- log.LOGGER.error(
- "File '%s' not found for rights management type 'regex'" % FILENAME)
- return regex
-
- def _read_from_sections(user, collection, perm):
- """Get regex sections."""
- regex = _read_regex(user, collection)
- try:
- for section in regex.sections():
- if _matches_section(user, collection, section):
- if perm in regex.get(section, "permission"):
- return True
- except (NoSectionError, NoOptionError):
- return False
- return False
-
- def _matches_section(user, collection, section):
- """Regex section against user and collection"""
- log.LOGGER.debug("Reading regex from file %s" % FILENAME)
- regex = _read_regex(user, collection)
- log.LOGGER.debug("Match against section '%s'" % section)
- try:
- test = regex.get(section, 'glue')
- except (NoOptionError):
- test = user+'|'+collection;
-
- try:
- match = re.match(regex.get(section, 'regex'), test)
- if match:
- return True;
- log.LOGGER.debug("Test-String '%s' does not match against '%s' from section '%s'" % \
- (test, regex.get(section, 'regex'), section))
- except (NoSectionError, NoOptionError):
- return False
- return False
-
-
- def _get_secondary():
- """Get secondary rights management method"""
- try:
- secondary = config.get("rights", "regex_secondary")
- if not secondary or secondary == None:
- secondary = 'owner_only'
-
- root_module = __import__(
- "rights.%s" % secondary, globals=globals(), level=2)
- module = getattr(root_module, secondary)
- return module
- except (ImportError, NoSectionError, NoOptionError):
- return None
-
- def read_authorized(user, collection):
- """Check if the user is allowed to read the collection."""
- if user is None:
- return False
- elif _get_secondary() != None and _get_secondary().read_authorized(user, collection):
- return True
- else:
- return _read_from_sections(
- user, collection.url.rstrip("/") or "/", "r")
- def write_authorized(user, collection):
- """Check if the user is allowed to write the collection."""
- if user is None:
- return False
- elif _get_secondary() != None and _get_secondary().write_authorized(user, collection):
- return True
- else:
- return _read_from_sections(
- user, collection.url.rstrip("/") or "/", "w")
|