Change a couple of things in regex-based rights manager
This commit is contained in:
		
							
								
								
									
										8
									
								
								config
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								config
									
									
									
									
									
								
							| @@ -99,16 +99,10 @@ http_password_parameter = | ||||
| # Value: None | owner_only | owner_write | from_file | regex | ||||
| type = None | ||||
|  | ||||
| # File for rights management from_file | ||||
| # File for rights management from_file or regex | ||||
| file = ~/.config/radicale/rights | ||||
|  | ||||
|  | ||||
| # File for rights management regex | ||||
| regex_file =~/.config/radicale/regex | ||||
| # use this as alternative method | ||||
| regex_secondary = owner_only | ||||
|  | ||||
|  | ||||
| [storage] | ||||
| # Storage backend | ||||
| # Value: filesystem | database | ||||
|   | ||||
| @@ -74,9 +74,7 @@ INITIAL_CONFIG = { | ||||
|         "http_password_parameter": ""}, | ||||
|     "rights": { | ||||
|         "type": "None", | ||||
|         "file": "", | ||||
|         "regex_file": "", | ||||
|         "regex_secondary": "owner_only"}, | ||||
|         "file": ""}, | ||||
|     "storage": { | ||||
|         "type": "filesystem", | ||||
|         "filesystem_folder": os.path.expanduser( | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # This file is part of Radicale Server - Calendar Server | ||||
| # Copyright © 2012-2013 Guillaume Ayoub | ||||
| # Copyright © 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 | ||||
| @@ -19,142 +19,108 @@ | ||||
| """ | ||||
| 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"). | ||||
| "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 "/"s are trimmed from collection names. | ||||
|  | ||||
| Example: | ||||
| Leading or ending slashes are trimmed from collection's path. | ||||
|  | ||||
| Examples: | ||||
|  | ||||
| # This means all users starting with "admin" may read any collection | ||||
| [admin] | ||||
| regex: ^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] | ||||
| glue: %(collection)s | ||||
| regex: ^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: | ||||
| # 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] | ||||
| regex:  ^.+@(.+)\|.+@\1(/.+)?$ | ||||
| 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 | ||||
|  | ||||
| """ | ||||
|  | ||||
| import os.path | ||||
| import re | ||||
|  | ||||
| from radicale import config, log, rights | ||||
| from radicale import config, log | ||||
|  | ||||
| # Manage Python2/3 different modules | ||||
| # pylint: disable=F0401 | ||||
| try: | ||||
|     from configparser import ( | ||||
|         ConfigParser as ConfigParser, NoSectionError, NoOptionError) | ||||
|     from configparser import ConfigParser | ||||
| except ImportError: | ||||
|     from ConfigParser import ( | ||||
|         ConfigParser as ConfigParser, NoSectionError, NoOptionError) | ||||
|     from ConfigParser import ConfigParser | ||||
| # pylint: enable=F0401 | ||||
|  | ||||
|  | ||||
| FILENAME = ( | ||||
|     os.path.expanduser(config.get("rights", "regex_file")) or | ||||
|     os.path.expanduser(config.get("rights", "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}) | ||||
|  | ||||
|  | ||||
| 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) | ||||
|     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"): | ||||
|             "File '%s' not found for rights management type 'regex'" % | ||||
|             FILENAME) | ||||
|         return False | ||||
|  | ||||
|     for section in regex.sections(): | ||||
|         re_user = regex.get(section, "user") | ||||
|         re_collection = regex.get(section, "collection") | ||||
|         log.LOGGER.debug( | ||||
|             "Test if '%s:%s' matches against '%s:%s' from section '%s'" % ( | ||||
|                 user, collection, re_user, re_collection, section)) | ||||
|         user_match = re.match(re_user, user) | ||||
|         if user_match: | ||||
|             re_collection = re_collection.format(*user_match.groups()) | ||||
|             if re.match(re_collection, collection): | ||||
|                 log.LOGGER.debug("Section '%s' matches" % section) | ||||
|                 if permission 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) | ||||
|         log.LOGGER.debug("Section '%s' does not match" % 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") | ||||
|     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.""" | ||||
|     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") | ||||
|     return user and _read_from_sections( | ||||
|         user, collection.url.rstrip("/") or "/", "w") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Guillaume Ayoub
					Guillaume Ayoub