def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" super(HTTPSServer, self).__init__(address, handler, False) # Test if the SSL files can be read for name in ("certificate", "key"): filename = config.get("server", name) try: open(filename, "r").close() except IOError as exception: log.LOGGER.warning( "Error while reading SSL %s %r: %s" % ( name, filename, exception)) ssl_kwargs = dict( server_side=True, certfile=config.get("server", "certificate"), keyfile=config.get("server", "key"), ssl_version=getattr( ssl, config.get("server", "protocol"), ssl.PROTOCOL_SSLv23)) # add ciphers argument only if supported (Python 2.7+) if sys.version_info >= (2, 7): ssl_kwargs["ciphers"] = config.get("server", "ciphers") or None self.socket = ssl.wrap_socket(self.socket, **ssl_kwargs) self.server_bind() self.server_activate()
def load(): """Load list of available storage managers.""" storage_type = config.get("rights", "type") if storage_type == "custom": rights_module = config.get("rights", "custom_handler") __import__(rights_module) module = sys.modules[rights_module] else: root_module = __import__("rights.regex", globals=globals(), level=2) module = root_module.regex sys.modules[__name__].authorized = module.authorized return module
def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" super(HTTPSServer, self).__init__(address, handler, False) self.socket = ssl.wrap_socket( self.socket, server_side=True, certfile=config.get("server", "certificate"), keyfile=config.get("server", "key"), ssl_version=ssl.PROTOCOL_SSLv23) self.server_bind() self.server_activate()
def get_path(): from werkzeug.exceptions import BadRequestKeyError try: path = request.args['path'] except BadRequestKeyError: path = request.form['path'] return path[len(config.get("server", "base_prefix").rstrip('/')):] if isinstance(path, str) else None
def _sha1(hash_value, password): """Check if ``hash_value`` and ``password`` match using sha1 method.""" hash_value = hash_value.replace("{SHA}", "").encode("ascii") password = password.encode(config.get("encoding", "stock")) sha1 = hashlib.sha1() # pylint: disable=E1101 sha1.update(password) return sha1.digest() == base64.b64decode(hash_value)
def __init__(self): """Initialize application.""" super(Application, self).__init__() self.acl = acl.load() self.encoding = config.get("encoding", "request") if config.getboolean('logging', 'full_environment'): self.headers_log = lambda environ: environ
def get_path(): from werkzeug.exceptions import BadRequestKeyError try: path = request.args['path'] except BadRequestKeyError: path = request.form['path'] return path[len(config.get("server", "base_prefix").rstrip('/') ):] if isinstance(path, str) else None
def __call__(self, environ, start_response): prefix = config.get("server", "base_prefix").rstrip('/') if environ['PATH_INFO'] in [prefix+'/import', prefix+'/export']: radicale.log.LOGGER.debug('Handing over to import app (stripped %s)' % prefix) environ['PATH_INFO'] = environ['PATH_INFO'][len(prefix):] return self.importapp.__call__(environ, start_response) return self.radicale.__call__(environ, start_response)
def __init__(self): """Initialize application.""" super(Application, self).__init__() self.acl = acl.load() storage.load() self.encoding = config.get("encoding", "request") if config.getboolean('logging', 'full_environment'): self.headers_log = lambda environ: environ
def __init__(self): """Initialize application.""" super(Application, self).__init__() auth.load() storage.load() rights.load() self.encoding = config.get("encoding", "request") if config.getboolean("logging", "full_environment"): self.headers_log = lambda environ: environ
def _config_users(name): """Get an iterable of strings from the configuraton string [acl] ``name``. The values must be separated by a comma. The whitespace characters are stripped at the beginning and at the end of the values. """ for user in config.get("acl", name).split(","): user = user.strip() yield None if user == "None" else user
def load(): """Load list of available ACL managers.""" acl_type = config.get("acl", "type") if acl_type == "None": return None else: PUBLIC_USERS.extend(_config_users("public_users")) PRIVATE_USERS.extend(_config_users("private_users")) module = __import__("acl.%s" % acl_type, globals=globals(), level=2) return getattr(module, acl_type)
def load(): """Load list of available ACL managers.""" acl_type = config.get("acl", "type") if acl_type == "None": return None else: PUBLIC_USERS.extend(_config_users("public_users")) PRIVATE_USERS.extend(_config_users("private_users")) module = __import__("radicale.acl", fromlist=[acl_type]) return getattr(module, acl_type)
def _ssha(hash_salt_value, password): """Check if ``hash_salt_value`` and ``password`` match using salted sha1 method.""" hash_salt_value = hash_salt_value.replace("{SSHA}", "").encode("ascii").decode('base64') password = password.encode(config.get("encoding", "stock")) hash_value = hash_salt_value[:20] salt_value = hash_salt_value[20:] sha1 = hashlib.sha1() # pylint: disable=E1101 sha1.update(password) sha1.update(salt_value) return sha1.digest() == hash_value
def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" super(HTTPSServer, self).__init__(address, handler, False) # Test if the SSL files can be read for name in ("certificate", "key"): filename = config.get("server", name) try: open(filename, "r").close() except IOError as exception: log.LOGGER.warn("Error while reading SSL %s %r: %s" % (name, filename, exception)) self.socket = ssl.wrap_socket(self.socket, server_side=True, certfile=config.get( "server", "certificate"), keyfile=config.get("server", "key"), ssl_version=ssl.PROTOCOL_SSLv23) self.server_bind() self.server_activate()
def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" super(HTTPSServer, self).__init__(address, handler, False) # Test if the SSL files can be read for name in ("certificate", "key"): filename = config.get("server", name) try: open(filename, "r").close() except IOError, (_, message): log.LOGGER.warn( "Error while reading SSL %s %r: %s" % ( name, filename, message))
def __init__(self, address, handler): """Create server by wrapping HTTP socket in an SSL socket.""" super(HTTPSServer, self).__init__(address, handler, False) # Test if the SSL files can be read for name in ("certificate", "key"): filename = config.get("server", name) try: open(filename, "r").close() except IOError as exception: log.LOGGER.warn( "Error while reading SSL %s %r: %s" % ( name, filename, exception)) self.socket = ssl.wrap_socket( self.socket, server_side=True, certfile=config.get("server", "certificate"), keyfile=config.get("server", "key"), ssl_version=ssl.PROTOCOL_SSLv23) self.server_bind() self.server_activate()
def _load(): read = {} write = {} file_name = config.get("rights", "file") if file_name == "None": log.LOGGER.error("No file name configured for rights type 'from_file'") return log.LOGGER.debug("Reading rights from file %s" % file_name) lines = open(file_name, "r").readlines() for line in lines: _process(line, read, write) global READ_AUTHORIZED, WRITE_AUTHORIZED READ_AUTHORIZED = read WRITE_AUTHORIZED = write
def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" global CONNEXION if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False try: CONNEXION.whoami_s() except: log.LOGGER.debug("Reconnecting the LDAP server") CONNEXION = ldap.initialize(config.get("acl", "ldap_url")) if BINDDN and PASSWORD: log.LOGGER.debug("Initial LDAP bind as %s" % BINDDN) CONNEXION.simple_bind_s(BINDDN, PASSWORD) distinguished_name = "%s=%s" % (ATTRIBUTE, ldap.dn.escape_dn_chars(user)) log.LOGGER.debug( "LDAP bind for %s in base %s" % (distinguished_name, BASE)) if FILTER: filter_string = "(&(%s)%s)" % (distinguished_name, FILTER) else: filter_string = distinguished_name log.LOGGER.debug("Used LDAP filter: %s" % filter_string) users = CONNEXION.search_s(BASE, SCOPE, filter_string) if users: log.LOGGER.debug("User %s found" % user) try: CONNEXION.simple_bind_s(users[0][0], password or "") except ldap.LDAPError: log.LOGGER.debug("Invalid credentials") else: log.LOGGER.debug("LDAP bind OK") return True else: log.LOGGER.debug("User %s not found" % user) log.LOGGER.debug("LDAP bind failed") return False
def _pretty_xml(element, level=0): """Indent an ElementTree ``element`` and its children.""" i = "\n" + level * " " if len(element): if not element.text or not element.text.strip(): element.text = i + " " if not element.tail or not element.tail.strip(): element.tail = i for sub_element in element: _pretty_xml(sub_element, level + 1) # ``sub_element`` is always defined as len(element) > 0 # pylint: disable=W0631 if not sub_element.tail or not sub_element.tail.strip(): sub_element.tail = i # pylint: enable=W0631 else: if level and (not element.tail or not element.tail.strip()): element.tail = i if not level: output_encoding = config.get("encoding", "request") return ('<?xml version="1.0"?>\n' + ET.tostring(element, "utf-8").decode("utf-8")).encode(output_encoding)
def _pretty_xml(element, level=0): """Indent an ElementTree ``element`` and its children.""" i = "\n" + level * " " if len(element): if not element.text or not element.text.strip(): element.text = i + " " if not element.tail or not element.tail.strip(): element.tail = i for sub_element in element: _pretty_xml(sub_element, level + 1) # ``sub_element`` is always defined as len(element) > 0 # pylint: disable=W0631 if not sub_element.tail or not sub_element.tail.strip(): sub_element.tail = i # pylint: enable=W0631 else: if level and (not element.tail or not element.tail.strip()): element.tail = i if not level: output_encoding = config.get("encoding", "request") return ('<?xml version="1.0"?>\n' + ET.tostring( element, "utf-8").decode("utf-8")).encode(output_encoding)
def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" global CONNEXION if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False try: CONNEXION.whoami_s() except: log.LOGGER.debug("Reconnecting the LDAP server") CONNEXION = ldap.initialize(config.get("acl", "ldap_url")) if BINDDN and PASSWORD: log.LOGGER.debug("Initial LDAP bind as %s" % BINDDN) CONNEXION.simple_bind_s(BINDDN, PASSWORD) distinguished_name = "%s=%s" % (ATTRIBUTE, ldap.dn.escape_dn_chars(user)) log.LOGGER.debug("LDAP bind for %s in base %s" % (distinguished_name, BASE)) users = CONNEXION.search_s(BASE, SCOPE, distinguished_name) if users: log.LOGGER.debug("User %s found" % user) try: CONNEXION.simple_bind_s(users[0][0], password or "") except ldap.LDAPError: log.LOGGER.debug("Invalid credentials") else: log.LOGGER.debug("LDAP bind OK") return True else: log.LOGGER.debug("User %s not found" % user) log.LOGGER.debug("LDAP bind failed") return False
def __call__(self, environ, start_response): """Manage a request.""" log.LOGGER.info("%s request at %s received" % ( environ["REQUEST_METHOD"], environ["PATH_INFO"])) headers = pprint.pformat(self.headers_log(environ)) log.LOGGER.debug("Request headers:\n%s" % headers) base_prefix = config.get("server", "base_prefix") if environ["PATH_INFO"].startswith(base_prefix): # Sanitize request URI environ["PATH_INFO"] = self.sanitize_uri( "/%s" % environ["PATH_INFO"][len(base_prefix):]) log.LOGGER.debug("Sanitized path: %s", environ["PATH_INFO"]) elif config.get("server", "can_skip_base_prefix"): log.LOGGER.debug( "Skipped already sanitized path: %s", environ["PATH_INFO"]) else: # Request path not starting with base_prefix, not allowed log.LOGGER.debug( "Path not starting with prefix: %s", environ["PATH_INFO"]) environ["PATH_INFO"] = None path = environ["PATH_INFO"] # Get function corresponding to method function = getattr(self, environ["REQUEST_METHOD"].lower()) # Ask authentication backend to check rights authorization = environ.get("HTTP_AUTHORIZATION", None) if authorization: authorization = authorization.lstrip("Basic").strip() user, password = self.decode(base64.b64decode( authorization.encode("ascii")), environ).split(":", 1) else: user = environ.get("REMOTE_USER") password = None well_known = WELL_KNOWN_RE.match(path) if well_known: redirect = config.get("well-known", well_known.group(1)) try: redirect = redirect % ({"user": user} if user else {}) except KeyError: status = client.UNAUTHORIZED headers = { "WWW-Authenticate": "Basic realm=\"%s\"" % config.get("server", "realm")} log.LOGGER.info( "Refused /.well-known/ redirection to anonymous user") else: status = client.SEE_OTHER log.LOGGER.info("/.well-known/ redirection to: %s" % redirect) if sys.version_info < (3, 0): redirect = redirect.encode(self.encoding) headers = {"Location": redirect} status = "%i %s" % ( status, client.responses.get(status, "Unknown")) start_response(status, list(headers.items())) return [] is_authenticated = auth.is_authenticated(user, password) is_valid_user = is_authenticated or not user if is_valid_user: items = ical.Collection.from_path( path, environ.get("HTTP_DEPTH", "0")) read_allowed_items, write_allowed_items = \ self.collect_allowed_items(items, user) else: read_allowed_items, write_allowed_items = None, None # Get content content_length = int(environ.get("CONTENT_LENGTH") or 0) if content_length: content = self.decode( environ["wsgi.input"].read(content_length), environ) log.LOGGER.debug("Request content:\n%s" % content) else: content = None if is_valid_user and ( (read_allowed_items or write_allowed_items) or (is_authenticated and function == self.propfind) or function == self.options): status, headers, answer = function( environ, read_allowed_items, write_allowed_items, content, user) else: status, headers, answer = NOT_ALLOWED if ((status, headers, answer) == NOT_ALLOWED and not auth.is_authenticated(user, password) and config.get("auth", "type") != "None"): # Unknown or unauthorized user log.LOGGER.info("%s refused" % (user or "Anonymous user")) status = client.UNAUTHORIZED headers = { "WWW-Authenticate": "Basic realm=\"%s\"" % config.get("server", "realm")} answer = None # Set content length if answer: log.LOGGER.debug( "Response content:\n%s" % self.decode(answer, environ)) headers["Content-Length"] = str(len(answer)) if config.has_section("headers"): for key in config.options("headers"): headers[key] = config.get("headers", key) # Start response status = "%i %s" % (status, client.responses.get(status, "Unknown")) log.LOGGER.debug("Answer status: %s" % status) start_response(status, list(headers.items())) # Return response content return [answer] if answer else []
def open(path, mode="r"): """Open a file at ``path`` with encoding set in the configuration.""" abs_path = os.path.join(Collection.get_folder(path), path.replace("/", os.sep)) return codecs.open(abs_path, mode, config.get("encoding", "stock"))
def get_folder(cls, path): home = pwd.getpwnam(cls.get_owner(path))[5] return home + config.get("storage", "filesystem_folder")[1:]
def _abs_path(path): return join(expanduser(get("storage", "filesystem_folder")), path.replace("/", sep))
# You should have received a copy of the GNU General Public License # along with Radicale. If not, see <http://www.gnu.org/licenses/>. """ PAM ACL. Authentication based on the ``pam-python`` module. """ import grp import pam import pwd from radicale import acl, config, log GROUP_MEMBERSHIP = config.get("acl", "pam_group_membership") def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False # Check whether the user exists in the PAM system try: pwd.getpwnam(user).pw_uid except KeyError: log.LOGGER.debug("User %s not found" % user) return False else:
def load(): """Load list of available storage managers.""" storage_type = config.get("storage", "type") module = __import__("radicale.storage", fromlist=[storage_type]) return getattr(module, storage_type)
def open(path, mode="r"): """Open a file at ``path`` with encoding set in the configuration.""" abs_path = os.path.join(FOLDER, path.replace("/", os.sep)) return codecs.open(abs_path, mode, config.get("encoding", "stock"))
user1: r """ 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 except ImportError: from ConfigParser import RawConfigParser as ConfigParser # pylint: enable=F0401 FILENAME = config.get("rights", "file") if FILENAME: log.LOGGER.debug("Reading rights from file %s" % FILENAME) RIGHTS = ConfigParser() RIGHTS.read(FILENAME) else: log.LOGGER.error("No file name configured for rights type 'from_file'") RIGHTS = None def read_authorized(user, collection): """Check if the user is allowed to read the collection.""" return ( owner_only.read_authorized(user, collection) or "r" in RIGHTS.get(collection.url.rstrip("/") or "/", user))
class Collection(icalCollection): _tz = gettz(get('storage', 'remind_timezone')) # Manually set timezone name to generate correct ical files # (python-vobject tests for the zone attribute) _tz.zone = get('storage', 'remind_timezone') _remind = Remind(expanduser(get('storage', 'remind_file')), _tz) _abook = Abook(expanduser(get('storage', 'abook_file'))) @staticmethod def _abs_path(path): return join(expanduser(get("storage", "filesystem_folder")), path.replace("/", sep)) def append(self, _, text): """Append items from ``text`` to collection. If ``name`` is given, give this name to new items in ``text``. """ if 'remind' in self.path: self._remind.append(text, self._abs_path(self.path)) if 'abook' in self.path: self._abook.append(text) def remove(self, name): """Remove object named ``name`` from collection.""" if 'remind' in self.path: self._remind.remove(name, self._abs_path(self.path)) if 'abook' in self.path: self._abook.remove(name) def replace(self, name, text): """Replace content by ``text`` in collection object called ``name``.""" if 'remind' in self.path: self._remind.replace(name, text, self._abs_path(self.path)) if 'abook' in self.path: self._abook.replace(name, text) def save(self, text): """Save the text into the collection.""" pass def delete(self): """Delete the collection.""" pass @property def text(self): """Collection as plain text.""" if 'remind' in self.path: return self._remind.to_vobject(self._abs_path( self.path)).serialize().decode('utf-8') if 'abook' in self.path: return self._abook.to_vcf().decode('utf-8') return "" @classmethod def children(cls, path): """Yield the children of the collection at local ``path``.""" children = [] for filename in cls._remind.get_filesnames(): children.append(cls(filename.replace(cls._abs_path(path), path))) children.append( cls(cls._abook.filename.replace(cls._abs_path(path), path))) return children @classmethod def is_node(cls, path): """Return ``True`` if relative ``path`` is a node. A node is a WebDAV collection whose members are other collections. """ return isdir(cls._abs_path(path)) @classmethod def is_leaf(cls, path): """Return ``True`` if relative ``path`` is a leaf. A leaf is a WebDAV collection whose members are not collections. """ return isfile(cls._abs_path(path)) @property def last_modified(self): """Get the last time the collection has been modified. The date is formatted according to rfc1123-5.2.14. """ return strftime('%a, %d %b %Y %H:%M:%S +0000', gmtime(getmtime(self._abs_path(self.path)))) @property @contextmanager def props(self): """Get the collection properties.""" # On enter if 'remind' in self.path: yield { 'tag': 'VCALENDAR', 'ICAL:calendar-color': '#%06x' % (hash(basename(self.path)) % 0xffffff) } elif 'abook' in self.path: yield {'tag': 'VADDRESSBOOK'} else: yield {}
""" from datetime import datetime import codecs from contextlib import contextmanager import json import os import posixpath import time import uuid from radicale import config FOLDER = os.path.expanduser(config.get("storage", "folder")) # This function overrides the builtin ``open`` function for this module # pylint: disable=W0622 def open(path, mode="r"): """Open file at ``path`` with ``mode``, automagically managing encoding.""" return codecs.open(path, mode, config.get("encoding", "stock")) # pylint: enable=W0622 def serialize(headers=(), items=()): """Return an iCal text corresponding to given ``headers`` and ``items``.""" lines = ["BEGIN:VCALENDAR"] for part in (headers, items): if part:
""" Htpasswd ACL. Load the list of login/password couples according a the configuration file created by Apache ``htpasswd`` command. Plain-text, crypt and sha1 are supported, but md5 is not (see ``htpasswd`` man page to understand why). """ import base64 import hashlib from radicale import acl, config FILENAME = config.get("acl", "htpasswd_filename") ENCRYPTION = config.get("acl", "htpasswd_encryption") def _plain(hash_value, password): """Check if ``hash_value`` and ``password`` match using plain method.""" return hash_value == password def _crypt(hash_value, password): """Check if ``hash_value`` and ``password`` match using crypt method.""" # The ``crypt`` module is only present on Unix, import if needed import crypt return crypt.crypt(password, hash_value) == hash_value
class Collection(icalCollection): _abook = Abook(expanduser(get('storage', 'abook_file'))) @staticmethod def _abs_path(path): return join(expanduser(get("storage", "filesystem_folder")), path.replace("/", sep)) def append(self, _, text): """Append items from ``text`` to collection. If ``name`` is given, give this name to new items in ``text``. """ if 'abook' in self.path: self._abook.append(text) def remove(self, name): """Remove object named ``name`` from collection.""" if 'abook' in self.path: self._abook.remove(name) def replace(self, name, text): """Replace content by ``text`` in collection object called ``name``.""" if 'abook' in self.path: self._abook.replace(name, text) def save(self, text): """Save the text into the collection.""" pass def delete(self): """Delete the collection.""" pass @property def text(self): """Collection as plain text.""" if 'abook' in self.path: return self._abook.to_vcf().decode('utf-8') return "" @classmethod def children(cls, path): """Yield the children of the collection at local ``path``.""" children = [] children.append( cls(cls._abook.filename.replace(cls._abs_path(path), path))) return children @classmethod def is_node(cls, path): """Return ``True`` if relative ``path`` is a node. A node is a WebDAV collection whose members are other collections. """ return isdir(cls._abs_path(path)) @classmethod def is_leaf(cls, path): """Return ``True`` if relative ``path`` is a leaf. A leaf is a WebDAV collection whose members are not collections. """ return isfile(cls._abs_path(path)) @property def last_modified(self): """Get the last time the collection has been modified. The date is formatted according to rfc1123-5.2.14. """ return strftime('%a, %d %b %Y %H:%M:%S +0000', gmtime(getmtime(self._abs_path(self.path)))) @property @contextmanager def props(self): """Get the collection properties.""" # On enter if 'abook' in self.path: yield {'tag': 'VADDRESSBOOK'} else: yield {}
# 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/>. """ LDAP ACL. Authentication based on the ``python-ldap`` module (http://www.python-ldap.org/). """ import ldap from radicale import acl, config, log BASE = config.get("acl", "ldap_base") ATTRIBUTE = config.get("acl", "ldap_attribute") CONNEXION = ldap.initialize(config.get("acl", "ldap_url")) BINDDN = config.get("acl", "ldap_binddn") PASSWORD = config.get("acl", "ldap_password") SCOPE = getattr(ldap, "SCOPE_%s" % config.get("acl", "ldap_scope").upper()) def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" global CONNEXION if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False
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."""
def open(path, mode="r"): """Open file at ``path`` with ``mode``, automagically managing encoding.""" return codecs.open(path, mode, config.get("encoding", "stock"))
""" from radicale import config, log from radicale.rights import owner_only from radicale.models.redmine import Users import os # Manage Python2/3 different modules # pylint: disable=F0401 try: from configparser import RawConfigParser as ConfigParser except ImportError: from ConfigParser import RawConfigParser as ConfigParser # pylint: enable=F0401 FILENAME = config.get("rights", "file") STORAGE_PATH = config.get("storage", "filesystem_folder") if FILENAME: log.LOGGER.debug("Reading rights from file %s" % FILENAME) RIGHTS = ConfigParser() RIGHTS.read(FILENAME) else: log.LOGGER.error("No file name configured for rights type 'from_file'") RIGHTS = None def create_group_dir(group): group_dir = os.path.join(STORAGE_PATH, 'groups', group) if not os.path.exists(group_dir): os.makedirs(group_dir)
def load(): """Load list of available storage managers.""" storage_type = config.get("storage", "type") module = __import__( "storage.%s" % storage_type, globals=globals(), level=2) return getattr(module, storage_type)
# You should have received a copy of the GNU General Public License # along with Radicale. If not, see <http://www.gnu.org/licenses/>. """ LDAP ACL. Authentication based on the ``python-ldap`` module (http://www.python-ldap.org/). """ import ldap from radicale import acl, config, log BASE = config.get("acl", "ldap_base") ATTRIBUTE = config.get("acl", "ldap_attribute") CONNEXION = ldap.initialize(config.get("acl", "ldap_url")) BINDDN = config.get("acl", "ldap_binddn") PASSWORD = config.get("acl", "ldap_password") def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False if BINDDN and PASSWORD: log.LOGGER.debug("Initial LDAP bind as %s" % BINDDN) CONNEXION.simple_bind_s(BINDDN, PASSWORD)
""" PAM ACL. Authentication based on the ``pam-python`` module. """ import grp import pam import pwd from radicale import acl, config, log GROUP_MEMBERSHIP = config.get("acl", "pam_group_membership") def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False # Check whether the user exists in the PAM system try: pwd.getpwnam(user).pw_uid except KeyError: log.LOGGER.debug("User %s not found" % user) return False else:
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. """ Htpasswd ACL. Load the list of login/password couples according a the configuration file created by Apache ``htpasswd`` command. Plain-text, crypt and sha1 are supported, but md5 is not (see ``htpasswd`` man page to understand why). """ import base64 import hashlib from radicale import acl, config FILENAME = config.get("acl", "htpasswd_filename") ENCRYPTION = config.get("acl", "htpasswd_encryption") def _plain(hash_value, password): """Check if ``hash_value`` and ``password`` match using plain method.""" return hash_value == password def _crypt(hash_value, password): """Check if ``hash_value`` and ``password`` match using crypt method.""" # The ``crypt`` module is only present on Unix, import if needed import crypt return crypt.crypt(password, hash_value) == hash_value
# You should have received a copy of the GNU General Public License # along with Radicale. If not, see <http://www.gnu.org/licenses/>. """ Filesystem storage backend. """ import codecs import os import json import time from contextlib import contextmanager from radicale import config, ical FOLDER = os.path.expanduser(config.get("storage", "filesystem_folder")) # This function overrides the builtin ``open`` function for this module # pylint: disable=W0622 def open(path, mode="r"): """Open a file at ``path`` with encoding set in the configuration.""" abs_path = os.path.join(FOLDER, path.replace("/", os.sep)) return codecs.open(abs_path, mode, config.get("encoding", "stock")) # pylint: enable=W0622 class Collection(ical.Collection): """Collection stored in a flat ical file."""
# 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/>. """ Courier-Authdaemon ACL. """ import sys import socket from radicale import acl, config, log COURIER_SOCKET = config.get("acl", "courier_socket") def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False line = "%s\nlogin\n%s\n%s" % (sys.argv[0], user, password) line = "%i\n%s" % (len(line), line) try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(COURIER_SOCKET) log.LOGGER.debug("Sending to Courier socket the request: %s" % line) sock.send(line)
user1: r """ 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 = config.get("rights", "file") if FILENAME: log.LOGGER.debug("Reading rights from file %s" % FILENAME) RIGHTS = ConfigParser() RIGHTS.read(FILENAME) else: log.LOGGER.error("No file name configured for rights type 'from_file'") RIGHTS = None 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
# You should have received a copy of the GNU General Public License # along with Radicale. If not, see <http://www.gnu.org/licenses/>. """ LDAP ACL. Authentication based on the ``python-ldap`` module (http://www.python-ldap.org/). """ import ldap from radicale import acl, config, log BASE = config.get("acl", "ldap_base") ATTRIBUTE = config.get("acl", "ldap_attribute") CONNEXION = ldap.initialize(config.get("acl", "ldap_url")) BINDDN = config.get("acl", "ldap_binddn") PASSWORD = config.get("acl", "ldap_password") SCOPE = getattr(ldap, "SCOPE_%s" % config.get("acl", "ldap_scope").upper()) def has_right(owner, user, password): """Check if ``user``/``password`` couple is valid.""" global CONNEXION if not user or (owner not in acl.PRIVATE_USERS and user != owner): # No user given, or owner is not private and is not user, forbidden return False