This commit is contained in:
Corentin Le Bail 2011-02-16 13:53:27 +01:00
parent 8a86f57304
commit 50919133ac
6 changed files with 64 additions and 5 deletions

6
config
View File

@ -42,4 +42,10 @@ encryption = crypt
# created if not present # created if not present
folder = ~/.config/radicale/calendars folder = ~/.config/radicale/calendars
[Logging]
# Logging filename
logfile = ~/.config/radicale/radicale.log
# Log facility 10: DEBUG, 20: INFO, 30 WARNING, 40 ERROR, 50 CRITICAL
facility = 50
# vim:ft=cfg # vim:ft=cfg

View File

@ -46,13 +46,14 @@ except ImportError:
import BaseHTTPServer as server import BaseHTTPServer as server
# pylint: enable=F0401 # pylint: enable=F0401
from radicale import acl, config, ical, xmlutils from radicale import acl, config, ical, xmlutils, log
VERSION = "git" VERSION = "git"
def _check(request, function): def _check(request, function):
"""Check if user has sufficient rights for performing ``request``.""" """Check if user has sufficient rights for performing ``request``."""
log.log(10, "Check if user has sufficient rights for performing ``request``.")
# ``_check`` decorator can access ``request`` protected functions # ``_check`` decorator can access ``request`` protected functions
# pylint: disable=W0212 # pylint: disable=W0212
authorization = request.headers.get("Authorization", None) authorization = request.headers.get("Authorization", None)
@ -64,8 +65,10 @@ def _check(request, function):
user = password = None user = password = None
if request.server.acl.has_right(request._calendar.owner, user, password): if request.server.acl.has_right(request._calendar.owner, user, password):
log.log(20, "Sufficient rights for performing ``request``.")
function(request) function(request)
else: else:
log.log(40, "No sufficient rights for performing ``request``.")
request.send_response(client.UNAUTHORIZED) request.send_response(client.UNAUTHORIZED)
request.send_header( request.send_header(
"WWW-Authenticate", "WWW-Authenticate",
@ -82,6 +85,7 @@ class HTTPServer(server.HTTPServer):
# pylint: disable=W0231 # pylint: disable=W0231
def __init__(self, address, handler): def __init__(self, address, handler):
"""Create server.""" """Create server."""
log.log(10, "Create HTTP server.")
server.HTTPServer.__init__(self, address, handler) server.HTTPServer.__init__(self, address, handler)
self.acl = acl.load() self.acl = acl.load()
# pylint: enable=W0231 # pylint: enable=W0231
@ -92,6 +96,7 @@ class HTTPSServer(HTTPServer):
PROTOCOL = "https" PROTOCOL = "https"
def __init__(self, address, handler): def __init__(self, address, handler):
"""Create server by wrapping HTTP socket in an SSL socket.""" """Create server by wrapping HTTP socket in an SSL socket."""
log.log(10, "Create server by wrapping HTTP socket in an SSL socket.")
# Fails with Python 2.5, import if needed # Fails with Python 2.5, import if needed
# pylint: disable=F0401 # pylint: disable=F0401
import ssl import ssl
@ -110,6 +115,7 @@ class HTTPSServer(HTTPServer):
class CalendarHTTPHandler(server.BaseHTTPRequestHandler): class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
"""HTTP requests handler for calendars.""" """HTTP requests handler for calendars."""
log.log(10, "HTTP requests handler for calendars.")
_encoding = config.get("encoding", "request") _encoding = config.get("encoding", "request")
# Decorator checking rights before performing request # Decorator checking rights before performing request
@ -118,6 +124,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
@property @property
def _calendar(self): def _calendar(self):
"""The ``ical.Calendar`` object corresponding to the given path.""" """The ``ical.Calendar`` object corresponding to the given path."""
log.log(10, "The ``ical.Calendar`` object corresponding to the given path.")
# ``self.path`` must be something like a posix path # ``self.path`` must be something like a posix path
# ``normpath`` should clean malformed and malicious request paths # ``normpath`` should clean malformed and malicious request paths
attributes = posixpath.normpath(self.path.strip("/")).split("/") attributes = posixpath.normpath(self.path.strip("/")).split("/")
@ -127,6 +134,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
def _decode(self, text): def _decode(self, text):
"""Try to decode text according to various parameters.""" """Try to decode text according to various parameters."""
log.log(10, "Try to decode text according to various parameters.")
# List of charsets to try # List of charsets to try
charsets = [] charsets = []
@ -153,12 +161,14 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
"""Manage GET request.""" """Manage GET request."""
log.log(10, "Manage GET request.")
self.do_HEAD() self.do_HEAD()
self.wfile.write(self._answer) self.wfile.write(self._answer)
@check_rights @check_rights
def do_HEAD(self): def do_HEAD(self):
"""Manage HEAD request.""" """Manage HEAD request."""
log.log(10, "Manage HEAD request.")
item_name = xmlutils.name_from_path(self.path) item_name = xmlutils.name_from_path(self.path)
if item_name: if item_name:
# Get calendar item # Get calendar item
@ -188,6 +198,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
@check_rights @check_rights
def do_DELETE(self): def do_DELETE(self):
"""Manage DELETE request.""" """Manage DELETE request."""
log.log(10, "Manage DELETE request.")
item = self._calendar.get_item(xmlutils.name_from_path(self.path)) item = self._calendar.get_item(xmlutils.name_from_path(self.path))
if item and self.headers.get("If-Match", item.etag) == item.etag: if item and self.headers.get("If-Match", item.etag) == item.etag:
# No ETag precondition or precondition verified, delete item # No ETag precondition or precondition verified, delete item
@ -203,6 +214,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
def do_OPTIONS(self): def do_OPTIONS(self):
"""Manage OPTIONS request.""" """Manage OPTIONS request."""
log.log(10, "Manage OPTIONS request.")
self.send_response(client.OK) self.send_response(client.OK)
self.send_header( self.send_header(
"Allow", "DELETE, HEAD, GET, OPTIONS, PROPFIND, PUT, REPORT") "Allow", "DELETE, HEAD, GET, OPTIONS, PROPFIND, PUT, REPORT")
@ -211,6 +223,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
def do_PROPFIND(self): def do_PROPFIND(self):
"""Manage PROPFIND request.""" """Manage PROPFIND request."""
log.log(10, "Manage PROPFIND request.")
xml_request = self.rfile.read(int(self.headers["Content-Length"])) xml_request = self.rfile.read(int(self.headers["Content-Length"]))
self._answer = xmlutils.propfind( self._answer = xmlutils.propfind(
self.path, xml_request, self._calendar, self.path, xml_request, self._calendar,
@ -226,6 +239,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
@check_rights @check_rights
def do_PUT(self): def do_PUT(self):
"""Manage PUT request.""" """Manage PUT request."""
log.log(10, "Manage PUT request.")
item_name = xmlutils.name_from_path(self.path) item_name = xmlutils.name_from_path(self.path)
item = self._calendar.get_item(item_name) item = self._calendar.get_item(item_name)
if (not item and not self.headers.get("If-Match")) or \ if (not item and not self.headers.get("If-Match")) or \
@ -249,6 +263,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
@check_rights @check_rights
def do_REPORT(self): def do_REPORT(self):
"""Manage REPORT request.""" """Manage REPORT request."""
log.log(10, "Manage REPORT request.")
xml_request = self.rfile.read(int(self.headers["Content-Length"])) xml_request = self.rfile.read(int(self.headers["Content-Length"]))
self._answer = xmlutils.report(self.path, xml_request, self._calendar) self._answer = xmlutils.report(self.path, xml_request, self._calendar)
@ -257,4 +272,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(self._answer) self.wfile.write(self._answer)
def log_message(self, format, *args):
log.log(10, format % (args))
# pylint: enable=C0103 # pylint: enable=C0103

View File

@ -2,7 +2,7 @@
import sys, ldap import sys, ldap
from radicale import config from radicale import config, log
def has_right(owner, user, password): def has_right(owner, user, password):
if user == None: if user == None:
@ -12,11 +12,15 @@ def has_right(owner, user, password):
if owner != user: if owner != user:
return False return False
try: try:
log.log(10, "Open LDAP server connexion")
l=ldap.open(LDAPSERVER, 389) l=ldap.open(LDAPSERVER, 389)
cn="%s%s,%s" % (LDAPPREPEND, user, LDAPAPPEND) cn="%s%s,%s" % (LDAPPREPEND, user, LDAPAPPEND)
log.log(10, "LDAP bind with dn: %s" %(cn))
l.simple_bind_s(cn, password); l.simple_bind_s(cn, password);
log.log(20, "LDAP bind Ok")
return True return True
except: except:
log.log(40, "LDAP bind error")
return False return False
LDAPSERVER = config.get("authLdap", "LDAPServer") LDAPSERVER = config.get("authLdap", "LDAPServer")

View File

@ -56,7 +56,10 @@ INITIAL_CONFIG = {
"filename": "/etc/radicale/users", "filename": "/etc/radicale/users",
"encryption": "crypt"}, "encryption": "crypt"},
"storage": { "storage": {
"folder": os.path.expanduser("~/.config/radicale/calendars")}} "folder": os.path.expanduser("~/.config/radicale/calendars")},
"logging": {
"logfile": os.path.expanduser("~/.config/radicale/radicale.log"),
"facility": 10}}
# Create a ConfigParser and configure it # Create a ConfigParser and configure it
_CONFIG_PARSER = ConfigParser() _CONFIG_PARSER = ConfigParser()

22
radicale/log.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
import logging, sys
from radicale import config
class log:
def __init__(self):
self.logger=logging.getLogger("radicale")
self.logger.setLevel(config.get("logging", "facility"))
handler=logging.FileHandler(config.get("logging", "logfile"))
formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
def log(self, level, msg):
self.logger.log(level, msg)
_LOGGING = log()
sys.modules[__name__] = _LOGGING

View File

@ -31,7 +31,7 @@ in them for XML requests (all but PUT).
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from radicale import client, config, ical from radicale import client, config, ical, log
NAMESPACES = { NAMESPACES = {
@ -47,11 +47,13 @@ def _tag(short_name, local):
def _response(code): def _response(code):
"""Return full W3C names from HTTP status codes.""" """Return full W3C names from HTTP status codes."""
log.log(10, "Return full W3C names from HTTP status codes.")
return "HTTP/1.1 %i %s" % (code, client.responses[code]) return "HTTP/1.1 %i %s" % (code, client.responses[code])
def name_from_path(path): def name_from_path(path):
"""Return Radicale item name from ``path``.""" """Return Radicale item name from ``path``."""
log.log(10, "Return Radicale item name from ``path``.")
return path.split("/")[-1] return path.split("/")[-1]
@ -62,6 +64,7 @@ def delete(path, calendar):
""" """
# Reading request # Reading request
log.log(10, "Read and answer DELETE requests.")
calendar.remove(name_from_path(path)) calendar.remove(name_from_path(path))
# Writing answer # Writing answer
@ -87,8 +90,9 @@ def propfind(path, xml_request, calendar, depth, request):
""" """
# Reading request # Reading request
log.log(10, "Read and answer PROPFIND requests.")
root = ET.fromstring(xml_request) root = ET.fromstring(xml_request)
prop_element = root.find(_tag("D", "prop")) prop_element = root.find(_tag("D", "prop"))
prop_list = prop_element.getchildren() prop_list = prop_element.getchildren()
props = [prop.tag for prop in prop_list] props = [prop.tag for prop in prop_list]
@ -164,6 +168,7 @@ def propfind(path, xml_request, calendar, depth, request):
def put(path, ical_request, calendar): def put(path, ical_request, calendar):
"""Read PUT requests.""" """Read PUT requests."""
log.log(10, "Read PUT requests.")
name = name_from_path(path) name = name_from_path(path)
if name in (item.name for item in calendar.items): if name in (item.name for item in calendar.items):
# PUT is modifying an existing item # PUT is modifying an existing item
@ -180,6 +185,7 @@ def report(path, xml_request, calendar):
""" """
# Reading request # Reading request
log.log(10, "Read and answer REPORT requests.")
root = ET.fromstring(xml_request) root = ET.fromstring(xml_request)
prop_element = root.find(_tag("D", "prop")) prop_element = root.find(_tag("D", "prop"))