Merge branch 'master' into lightning
This commit is contained in:
commit
264bc66051
3
NEWS
3
NEWS
@ -14,7 +14,8 @@
|
|||||||
* Smart, verbose and configurable logs
|
* Smart, verbose and configurable logs
|
||||||
* Apple iCal 4 and iPhone support (by Łukasz Langa)
|
* Apple iCal 4 and iPhone support (by Łukasz Langa)
|
||||||
* LDAP auth backend (by Corentin Le Bail)
|
* LDAP auth backend (by Corentin Le Bail)
|
||||||
* Owner-less calendars (by René Neumann)
|
* Public and private calendars (by René Neumann)
|
||||||
|
* PID file
|
||||||
* Journal entries support
|
* Journal entries support
|
||||||
* Drop Python 2.5 support
|
* Drop Python 2.5 support
|
||||||
|
|
||||||
|
4
config
4
config
@ -36,6 +36,10 @@ stock = utf-8
|
|||||||
# Access method
|
# Access method
|
||||||
# Value: None | htpasswd | LDAP
|
# Value: None | htpasswd | LDAP
|
||||||
type = None
|
type = None
|
||||||
|
# Usernames used for public calendars, separated by a comma
|
||||||
|
public_users = public
|
||||||
|
# Usernames used for private calendars, separated by a comma
|
||||||
|
private_users = private
|
||||||
# Htpasswd filename
|
# Htpasswd filename
|
||||||
htpasswd_filename = /etc/radicale/users
|
htpasswd_filename = /etc/radicale/users
|
||||||
# Htpasswd encryption method
|
# Htpasswd encryption method
|
||||||
|
@ -32,6 +32,7 @@ Launch the server according to configuration and command-line options.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import atexit
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import optparse
|
import optparse
|
||||||
@ -101,6 +102,14 @@ if options.daemon:
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
sys.stdout = sys.stderr = open(os.devnull, "w")
|
sys.stdout = sys.stderr = open(os.devnull, "w")
|
||||||
|
|
||||||
|
# Register exit function
|
||||||
|
def cleanup():
|
||||||
|
radicale.log.LOGGER.debug("Cleaning up")
|
||||||
|
# Remove PID file
|
||||||
|
if options.pid and options.daemon:
|
||||||
|
os.unlink(options.pid)
|
||||||
|
|
||||||
|
atexit.register(cleanup)
|
||||||
radicale.log.LOGGER.info("Starting Radicale")
|
radicale.log.LOGGER.info("Starting Radicale")
|
||||||
|
|
||||||
# Create calendar servers
|
# Create calendar servers
|
||||||
|
26
radicale.wsgi
Executable file
26
radicale.wsgi
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# This file is part of Radicale Server - Calendar Server
|
||||||
|
# Copyright © 2011 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/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Radicale WSGI file (mod_wsgi and uWSGI compliant).
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import radicale
|
||||||
|
application = radicale.Application()
|
@ -183,16 +183,24 @@ class Application(object):
|
|||||||
if last_allowed:
|
if last_allowed:
|
||||||
calendars.append(calendar)
|
calendars.append(calendar)
|
||||||
continue
|
continue
|
||||||
log.LOGGER.info(
|
|
||||||
"Checking rights for calendar owned by %s" % calendar.owner)
|
|
||||||
|
|
||||||
if self.acl.has_right(calendar.owner, user, password):
|
if calendar.owner in acl.PUBLIC_USERS:
|
||||||
log.LOGGER.info("%s allowed" % (user or "anonymous user"))
|
log.LOGGER.info("Public calendar")
|
||||||
calendars.append(calendar)
|
calendars.append(calendar)
|
||||||
last_allowed = True
|
last_allowed = True
|
||||||
else:
|
else:
|
||||||
log.LOGGER.info("%s refused" % (user or "anonymous user"))
|
log.LOGGER.info(
|
||||||
last_allowed = False
|
"Checking rights for calendar owned by %s" % (
|
||||||
|
calendar.owner or "nobody"))
|
||||||
|
if self.acl.has_right(calendar.owner, user, password):
|
||||||
|
log.LOGGER.info(
|
||||||
|
"%s allowed" % (user or "Anonymous user"))
|
||||||
|
calendars.append(calendar)
|
||||||
|
last_allowed = True
|
||||||
|
else:
|
||||||
|
log.LOGGER.info(
|
||||||
|
"%s refused" % (user or "Anonymous user"))
|
||||||
|
last_allowed = False
|
||||||
|
|
||||||
if calendars:
|
if calendars:
|
||||||
status, headers, answer = function(environ, calendars, content)
|
status, headers, answer = function(environ, calendars, content)
|
||||||
|
@ -26,7 +26,7 @@ Authentication based on the ``python-ldap`` module
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap
|
import ldap
|
||||||
from radicale import config, log
|
from radicale import acl, config, log
|
||||||
|
|
||||||
|
|
||||||
BASE = config.get("acl", "ldap_base")
|
BASE = config.get("acl", "ldap_base")
|
||||||
@ -38,8 +38,8 @@ PASSWORD = config.get("acl", "ldap_password")
|
|||||||
|
|
||||||
def has_right(owner, user, password):
|
def has_right(owner, user, password):
|
||||||
"""Check if ``user``/``password`` couple is valid."""
|
"""Check if ``user``/``password`` couple is valid."""
|
||||||
if not user or (owner and user != owner):
|
if not user or (owner not in acl.PRIVATE_USERS and user != owner):
|
||||||
# No user given, or owner is set and is not user, forbidden
|
# No user given, or owner is not private and is not user, forbidden
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if BINDDN and PASSWORD:
|
if BINDDN and PASSWORD:
|
||||||
|
@ -29,11 +29,29 @@ configuration.
|
|||||||
from radicale import config
|
from radicale import config
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC_USERS = []
|
||||||
|
PRIVATE_USERS = []
|
||||||
|
|
||||||
|
|
||||||
|
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():
|
def load():
|
||||||
"""Load list of available ACL managers."""
|
"""Load list of available ACL managers."""
|
||||||
acl_type = config.get("acl", "type")
|
acl_type = config.get("acl", "type")
|
||||||
if acl_type == "None":
|
if acl_type == "None":
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
PUBLIC_USERS.extend(_config_users("public_users"))
|
||||||
|
PRIVATE_USERS.extend(_config_users("private_users"))
|
||||||
module = __import__("radicale.acl", fromlist=[acl_type])
|
module = __import__("radicale.acl", fromlist=[acl_type])
|
||||||
return getattr(module, acl_type)
|
return getattr(module, acl_type)
|
||||||
|
@ -30,7 +30,7 @@ supported, but md5 is not (see ``htpasswd`` man page to understand why).
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from radicale import config
|
from radicale import acl, config
|
||||||
|
|
||||||
|
|
||||||
FILENAME = config.get("acl", "htpasswd_filename")
|
FILENAME = config.get("acl", "htpasswd_filename")
|
||||||
@ -63,6 +63,6 @@ def has_right(owner, user, password):
|
|||||||
for line in open(FILENAME).readlines():
|
for line in open(FILENAME).readlines():
|
||||||
if line.strip():
|
if line.strip():
|
||||||
login, hash_value = line.strip().split(":")
|
login, hash_value = line.strip().split(":")
|
||||||
if login == user and (not owner or owner == user):
|
if login == user and (owner in acl.PRIVATE_USERS or owner == user):
|
||||||
return globals()["_%s" % ENCRYPTION](hash_value, password)
|
return globals()["_%s" % ENCRYPTION](hash_value, password)
|
||||||
return False
|
return False
|
||||||
|
@ -50,6 +50,8 @@ INITIAL_CONFIG = {
|
|||||||
"stock": "utf-8"},
|
"stock": "utf-8"},
|
||||||
"acl": {
|
"acl": {
|
||||||
"type": "None",
|
"type": "None",
|
||||||
|
"public_users": "public",
|
||||||
|
"private_users": "private",
|
||||||
"httpasswd_filename": "/etc/radicale/users",
|
"httpasswd_filename": "/etc/radicale/users",
|
||||||
"httpasswd_encryption": "crypt",
|
"httpasswd_encryption": "crypt",
|
||||||
"ldap_url": "ldap://localhost:389/",
|
"ldap_url": "ldap://localhost:389/",
|
||||||
@ -74,6 +76,8 @@ for section, values in INITIAL_CONFIG.items():
|
|||||||
|
|
||||||
_CONFIG_PARSER.read("/etc/radicale/config")
|
_CONFIG_PARSER.read("/etc/radicale/config")
|
||||||
_CONFIG_PARSER.read(os.path.expanduser("~/.config/radicale/config"))
|
_CONFIG_PARSER.read(os.path.expanduser("~/.config/radicale/config"))
|
||||||
|
if 'RADICALE_CONFIG' in os.environ:
|
||||||
|
_CONFIG_PARSER.read(os.environ['RADICALE_CONFIG'])
|
||||||
|
|
||||||
# Wrap config module into ConfigParser instance
|
# Wrap config module into ConfigParser instance
|
||||||
sys.modules[__name__] = _CONFIG_PARSER
|
sys.modules[__name__] = _CONFIG_PARSER
|
||||||
|
1
setup.py
1
setup.py
@ -88,7 +88,6 @@ setup(
|
|||||||
"Programming Language :: Python :: 2.6",
|
"Programming Language :: Python :: 2.6",
|
||||||
"Programming Language :: Python :: 2.7",
|
"Programming Language :: Python :: 2.7",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.0",
|
|
||||||
"Programming Language :: Python :: 3.1",
|
"Programming Language :: Python :: 3.1",
|
||||||
"Programming Language :: Python :: 3.2",
|
"Programming Language :: Python :: 3.2",
|
||||||
"Topic :: Office/Business :: Groupware"])
|
"Topic :: Office/Business :: Groupware"])
|
||||||
|
Loading…
Reference in New Issue
Block a user