Exemple #1
0
    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()
Exemple #2
0
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
Exemple #3
0
    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
Exemple #5
0
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)
Exemple #6
0
 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
Exemple #7
0
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)
Exemple #8
0
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
Exemple #9
0
    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)
Exemple #10
0
 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
Exemple #11
0
 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
Exemple #12
0
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
Exemple #13
0
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)
Exemple #14
0
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)
Exemple #15
0
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)
Exemple #16
0
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
Exemple #17
0
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
Exemple #18
0
    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()
Exemple #19
0
    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))
Exemple #20
0
    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()
Exemple #21
0
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
Exemple #22
0
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
Exemple #23
0
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)
Exemple #24
0
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)
Exemple #25
0
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
Exemple #26
0
    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:]
Exemple #29
0
 def _abs_path(path):
     return join(expanduser(get("storage", "filesystem_folder")),
                 path.replace("/", sep))
Exemple #30
0
# 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:
Exemple #31
0
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)
Exemple #32
0
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"))
Exemple #33
0
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))
Exemple #34
0
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 {}
Exemple #35
0
"""

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:
Exemple #36
0
"""
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

Exemple #37
0
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 {}
Exemple #38
0
# 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
Exemple #39
0
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."""
Exemple #40
0
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)
Exemple #42
0
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)
Exemple #43
0
# 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)
Exemple #44
0
"""
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:
Exemple #45
0
# 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

Exemple #46
0
# 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."""
Exemple #47
0
# 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)
Exemple #48
0
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
Exemple #49
0
# 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